在 Java 中实现多线程有两种手段,一种是继承 Thread 类,另一种就是实现 Runnable 接口。
线程状态
创建、就绪、阻塞、运行、终止
线程操作
join():一个线程强制运行,其他线程要运行必须等该线程结束之后才可以
sleep():线程休眠
interrupt():中断线程
setDaemon():后台线程
setPriority():线程优先级
yield():线程的礼让(一个线程调用此方法让其他线程先执行)
同步及死锁
同步代码块
synchronized(同步对象){
需要同步的代码
}
public class Ticket implements Runnable{
private int count = 5;
@Override
public void run() {
for(int i = 0; i < 100; i++){
synchronized (this) {
if(count > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ticket:" + count--);
}
}
}
}
}
同步方法
synchronized 方法返回值 方法名称(参数列表){
}
public class Ticket implements Runnable{
private int count = 5;
@Override
public void run() {
for(int i = 0; i < 100; i++){
sale();
}
}
public synchronized void sale(){
if(count > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ticket:" + count--);
}
}
}
死锁
同步可以保证资源共享操作的正确性,但是过多同步也会产生问题。例如,现在张三想要李四的画,李四想要张三的书,张三对李四说“把你的画给我,我就给你书”,李四也对张三说“把你的书给我,我就给你画”两个人互相等对方先行动,就这么干等没有结果,这实际上就是死锁的概念。
所谓死锁,就是两个线程都在等待对方先完成,造成程序的停滞,一般程序的死锁都是在程序运行时出现的。
同步关键字synchronized,总是会看见几种写法,修饰方法、修饰静态方法、synchronized(Xxx.class)、synchronized(this)、synchronized(obj)
。每个对象都有一个监视器monitor,被synchronized修饰,语义就是获取这个对象的monitor,反编译后可以看到monitorenter和monitorexit。synchronized关键字有三种应用方式:
修饰实例方法
修饰静态方法
修饰代码块(指定对象)
synchronized(Xxx.class)获取的是类的monitor,所以与public synchronized static void some()修饰静态方法是等价的
synchronized(this)获取的是当前实例的monitor,所以与public synchronized void some()修饰实例方法是等价的
synchronized(任意自定义对象)进行同步操作,对象监视器必须是同一个对象。不是同一个,运行就是异步执行了。
取得同一个monitor会发生同步。