join方法:将一个线程添加到另一个线程中,如将t1线程添加到t2线程中,然后启动t1、t2线程(t1在前t2在后),此时t1线程执行完后再执行t2线程,如果t2中join了多个线程,这几个线程交替执行完成后再执行t2,如果t2在前则join失效,两个线程交替执行
public static void main(String[] args) {
testJoin();
System.out.println("join test");
}
static void testJoin() {
Thread t1 = new Thread(()->{
for(int i=0; i<5; i++) {
System.out.println("A" + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(()->{
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0; i<5; i++) {
System.out.println("B" + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
System.out.println("--------------------");
t2.start();
}
sleep: sleep方法进入阻塞状态,特定时间后进入就绪状态 static void testSleep() { new Thread(()->{ for(int i=0; i<5; i++) { System.out.println("A" + i); try { Thread.sleep(50); //TimeUnit.Milliseconds.sleep(500) } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } yield: yield方法让出CPU进入就绪状态,可能让出后马上给你就能接着执行 static void testYield() { new Thread(()->{ for(int i=0; i<50; i++) { System.out.println("A" + i); if(i%10 == 0) Thread.yield(); } }).start(); new Thread(()->{ for(int i=0; i<50; i++) { System.out.println("--B" + i); if(i%10 == 0) Thread.yield(); } }).start(); }
sleep和yield的区别:
sleep() 方法给其他线程运行机会时不考虑线程的优先级,yield() 方法只会给相同优先级或更高优先级的线程运行的机会;
线程执行 sleep() 方法后进入阻塞状态,特定时间后进入就绪状态,线程执行 yield() 方法转入就绪状态,可能马上又执行;
sleep() 方法声明抛出 InterruptedException,yield() 方法没有声明抛出异常;
sleep() 方法需要指定时间参数,yield() 方法出让 CPU 的执行权时间由 JVM 控制;
volatile和synchnorized:
synchronized 给方法和代码块添加锁:
判断synchronized是否同步访问要看加锁的对象是不是一样的,加锁的对象:
类锁:static修饰的synchronized方法,所对象是xxxx.class
类对象锁:synchronized方法(synchronized的默认参数是类的实例),锁对象是类的 实例,和类锁不是一回事
对象锁:方法内部的synchronized(对象)方法块,对某个属性加锁
(1)、一个对象同时调用synchronized 方法和非synchronized方法,是可以同时运行的
(2)、一个对象调用两个 synchronized修饰的方法只能同步执行,因为方法是共用的类对象锁,如果一个方法出现异常释放锁,要通过try、catch防止另一个同步方法接着执行;如果是不同对象调用synchronized方法,这两个对象的执行互不影响;
(3)、synchronized 是可重入锁:一个线程中一个同步方法可以调用另一个同步方法,一个线程已经拥有了某个对象的锁,再次申请的时候仍然会得到该对象的锁
(4)、synchronized(Object):参数不要使用 常量String、Integer、Long 这样的基础数据 常量String 是指向内存中唯一的对象,被锁住后可能会影响其他的线程
Integer和Long 值可能会被修改
volatile:volatile 修饰的变量在线程之间可见(变量内部的属性修改是不可见的)、禁止指令重排序
volatile不能实现synchnorized的功能,比如两个线程同时读取A为1,此时同时修改为2,尽管线程间可见还是会有同步问题
synchronized的实践参考:记录一 :对象锁和类锁_yunfei_run的博客-CSDN博客