线程:
1)进程中负责程序执行的执行单元
2)依靠程序执行的顺序控制流,只能使用程序的资源和环境,共享进程的全部资源
3)有自己的堆栈和局部变量,没有单独的地址空间
4)CPU调度和分派的基本单位,持有程序计数器,寄存器,堆栈
进程:
1)系统资源分配和调度的独立单位
2)至少包含一个线程
3)拥有自己的资源
创建线程的方式:
1)继承Thread类,实现run方法
2)实现Runnable接口,实现run方法,用实现接口的实例作为Thread类的构造参数创建线程
3)使用callable方式
第一种使用方法:
创建MyCallable类实现callable
创建一个线程池ExecutorService
创建callable
创建一个Future
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future future = threadPool.submit(new Callable() {
public Integer call() throws Exception {
return new Random().nextInt(100);
}
});
try {
Thread.sleep(5000);// 可能做一些事情
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
线程状态
java语言定义了5中线程状态,在任意一个时间点,一个线程只能有一种状态,注意这是JAVA中的线程状态和传统意义定义的线程状态有一些小区别,在JAVA源码中的注释:这些状态是虚拟机状态,它不反映任何操作系统的线程状态。
1)新建状态(New):创建后尚未启动的线程
2)运行状态(Runable):Runable包括了操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能在等待着CPU分配执行时间。
3)无限期等待(Waiting):处于这种状态的线程不会被分配CPU执行时间,它们要等待其他线程显示唤醒。以下方法会让线程陷入无限等待状态:没有设置Timeout参数的wait()方法,没有设置Timeout参数的join()方法等。
4)限期等待(Timed Waiting):处于这种状态的线程也不会被CPU分配执行时间,不过无须等待被显示唤醒,而是在一定时间过后会由系统自动唤醒,以下方法会让线程陷入限期等待状态:sleep,设置了Timeout的wait和join等。
5)阻塞状态(Blocked):线程被阻塞,阻塞状态与等待状态的区别是阻塞状态在等着获取一个排他锁,这个时间在另外一个线程放弃这个锁时发生,而等待状态是在等待时间或等待被唤醒动作时发生。在程序等待进入同步区时,线程进入阻塞状态。
6)结束状态(Terminated):已终止的线程状态,线程已经结束执行。
状态之间转换关系
进程状态:
1、就绪(Ready)状态
当进程已分配到除CPU以外的所有必要资源后,只要在获得CPU,便可立即执行,进程这时的状态就称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将他们排成一个队列,称为就绪队列。
2、执行状态
进程已获得CPU,其程序正在执行。在单处理机系统中,只有一个进程处于执行状态;再多处理机系统中,则有多个进程处于执行状态。
3、阻塞状态
正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃处理机而处于暂停状态,亦即程序的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。
状态转换:
*无法直接转换:阻塞--运行,就绪--阻塞
JAVA线程间通信:
1)共享内存:读写主内存隐式通信(轮询读取状态),共享对象通信,通过Synchronized,volatile,semaphore等。
2)消息传递:wait和notify,lock锁里的condition
3)管道:PipedOutputStream管道输出流POS , PipedInputStream管道输入流PIS,匹配:pos.connect(pis);
例POS给生产者,PIS给消费者,匹配完成后再线程RUN方法中执行write和read方法,属于单向通信
进程间通信:
1)管道(pipe):具有亲缘关系的进程可以使用,运行一个进程和另一个有共同祖先的进程通信。
2)命名管道(named pipe):允许无亲缘关系的进程之间通信。
3)信号(signal):用于通知接收的进程有某种事情发生,也可进程对自身发送。
4)信号量(semaphore):主要用于进程间以及同一进程不同线程的同步手段,信号量可理解为同步资源数量(3个线程,2个信号量)
5)消息队列(Message):消息的链接表,有足够权限的进程可写入消息,被赋予读权限的进程可读取消息。克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
6)共享内存:使得多个进程可以访问同一块内存空间,可配合信号量使用。
7)内存映射:内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。网络编程。
线程同步的方式:
1)设置临界区(共享内存)
2)设置互斥量(lock锁)
3)设置事件(例如计数栓)
4)设置信号量(AQS共享锁)
死锁产生的四个必要条件(必须同时具备):
1)互斥条件:一个资源每一次只能被一个进程使用
2)请求与保持条件:一个进程因请求资源而阻塞时,对获得的资源保持不放
3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
4)循环等待条件:若干进程之间形成一种头尾相接的循环等待关系
避免死锁:
1)合理设置同步区,避免一个线程同时获取多个锁
2)尽量保证一个锁占用一个资源
3)使用tryLock(Timeout)代替内部锁,即加锁顺序,加锁时限
4)对于数据库锁,加解锁必须放在一个数据库连接里