一步步学习多线程(四) 多线程基础3(线程同步操作)

时间:2022-11-07 23:48:18

Java同步的两种方法synchronized 和 wait()、notify()

synchronized

      指定加锁对象:对给定对象(代码块)加锁,进入同步代码前要获得给定对象的锁

      直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁

      直接所用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁


实例一:

public class SynconizedOne implements Runnable{
static SynconizedOne instance = new SynconizedOne();
static int i = 0;
@Override
public void run() {
for (int j = 0; j < 1000000; j++) {
synchronized(instance){
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}

因为加了一把锁 instance,输出的结果就是2000000,如果不加synchronized(instance)这句话,那么得到的结果肯定小于2000000


实例2:

public class SynconizedTwo implements Runnable{
static SynconizedTwo instance = new SynconizedTwo();
static int i = 0;
public synchronized void increase(){
i++;
}
@Override
public void run() {
for (int j = 0; j < 1000000; j++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}

结果是2000000,由于两个线程用的是一把锁,结果才是2000000,如果两个线程分别执行的不同实例,那么结果会小于2000000,比如  

Thread t1 = new Thread(new SynconizedTwo());
Thread t2 = new Thread(new SynconizedTwo());


实例3:

把上面那个程序修改一下:

public class SynconizedFour implements Runnable{
//static SynconizedThree instance = new SynconizedThree();
static int i = 0;
public static synchronized void increase(){
i++;
}
@Override
public void run() {
for (int j = 0; j < 1000000; j++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new SynconizedFour());
Thread t2 = new Thread(new SynconizedFour());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
虽然开启的两个线程用的两个实例,但是由于方法是静态方法,则得到的结果依然是2000000

  

wait()、notify()、notifyAll()

wait():线程等待在当前对象上

notify():通知等待的对象一个线程返回,如果有多个,随机唤醒

notifyAll(): 唤醒所有的等待状态的对象

      wait() 与 notify/notifyAll 方法必须在同步代码块中使用


实例4:

public class WaitDemo {

final static Object obj = new Object();
public static class T1 extends Thread{

@Override
public void run() {
synchronized (obj) {
System.out.println(System.currentTimeMillis() + ":T1 wait for object");
try {
obj.wait();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + ":T1 end!");
}
}
}
public static class T2 extends Thread{

@Override
public void run() {
synchronized (obj) {
System.out.println(System.currentTimeMillis() + ":T2 start for object");
obj.notify();
System.out.println(System.currentTimeMillis() + ":T2 end!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
Thread.sleep(1000);
t2.start();
t1.join();
t2.join();
}
}

运行的结果:

1527061625808:T1 wait for object
1527061626809:T2 start for object
1527061626810:T2 end!
1527061628811:T1 end!

分析:首先T1先运行,拿到了obj这把锁,输出第一句话,然后wait,释放资源;然后T2拿到了这把锁,输出了第二句话,然后通知其他wait状态的对象返回。但是T1还需要拿到锁才能继续执行,而此时锁还在T2的手里,当T2执行完,输出第三句话时,T1才拿到锁,并继续执行。

notifyAll()的用法和 notify()一致,再次不多作描述