0
点赞
收藏
分享

微信扫一扫

多线程基础(三)

三维控件研究 2022-02-16 阅读 67

多线程基础(三)


一、线程通信

多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同。

1、共享内存方式通信(while轮询的方式)

public class ListAdd1 {

private static volatile List<String> list = new ArrayList<>();


public static void main(String[] args) {

Thread t1 = new Thread(()->{
for (int i = 0; i <10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add("element");
System.out.println(Thread.currentThread().getName() + "向list中添加了" + (i + 1) + "个元素");
}
},"t1");

Thread t2 = new Thread(()->{
System.out.println("进入t2线程...");
while(true) {
if (list.size() ==5) {
System.out.println("t2线程收到通知,线程结束...");
throw new RuntimeException();
}
}
},"t2");

t2.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.start();
}
}

  这种方式t1线程会不断地改变条件,线程t2不停的通过while语句检测list1.size() == 5是否成立,从而实现线程间的通信。但是这种方式会浪费CPU的资源。

2、wait/notify机制

   使用wait/notify方法实现线程间的通信。(注意这两个方法都是object类的方法,换句话说java为所有的对象都提供了这两个方法)

        ① wait和notify必须配合synchronized关键字使用

        ② wait方法释放锁,notify方法不释放锁

        ③ wait和notify要被同一个对象调用

public class ListAdd1 {

private static volatile List<String> list = new ArrayList<>();

public static void main(String[] args) {
//实例化出来一个 lock,当使用wait 和 notify 的时候 , 一定要配合着synchronized关键字去使用
final Object lock = new Object();

Thread t1 = new Thread(()->{
synchronized (lock){
for (int i = 0; i <10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add("element");
System.out.println(Thread.currentThread().getName() + "向list中添加了" + (i + 1) + "个元素");
if (i == 4) {
System.out.println("t1向t2发出通知");
lock.notify();
}
}
}
},"t1");

Thread t2 = new Thread(()->{
synchronized (lock) {
System.out.println("进入t2线程...");
if (list.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2线程收到通知,线程结束...");
throw new RuntimeException();
}
},"t2");

t2.start();
t1.start();
}
}

这种方式实时性比较差,可以使用CountDownLatch进行改进。

public class ListAdd1 {

private static volatile List<String> list = new ArrayList<>();

public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(1);

Thread t1 = new Thread(()->{
for (int i = 0; i <10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add("element");
System.out.println(Thread.currentThread().getName() + "向list中添加了" + (i + 1) + "个元素");
if (i == 4) {
System.out.println("t1向t2发出通知");
countDownLatch.countDown();
}
}
},"t1");

Thread t2 = new Thread(()->{
System.out.println("进入t2线程...");
if (list.size() != 5) {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2线程收到通知,线程结束...");
throw new RuntimeException();

},"t2");

t2.start();
t1.start();
}
}


二、使用wait/notify模型LinkedBlockQueue

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class MyQueue {

// 1 需要一个承装元素的集合
private LinkedList<Object> list = new LinkedList<Object>();

// 2 需要一个计数器
private AtomicInteger count = new AtomicInteger(0);

// 3 需要制定上限和下限
private final int minSize = 0;

private final int maxSize;

// 4 构造方法
public MyQueue(int size) {
this.maxSize = size;
}

// 5 初始化一个对象 用于加锁
private final Object lock = new Object();

// put(anObject):
// 把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间再继续.
public void put(Object obj) {
synchronized (lock) {
while (count.get() == this.maxSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 1 加入元素
list.add(obj);
// 2 计数器累加
count.incrementAndGet();
// 3 通知另外一个线程(唤醒)
lock.notify();
System.out.println("新加入的元素为:" + obj);
}
}

// take:
// 取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.
public Object take() {
Object ret = null;
synchronized (lock) {
while (count.get() == this.minSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 1 做移除元素操作
ret = list.removeFirst();
// 2 计数器递减
count.decrementAndGet();
// 3 唤醒另外一个线程
lock.notify();
}
return ret;
}

public int getSize() {
return this.count.get();
}

public static void main(String[] args) {

final MyQueue mq = new MyQueue(5);
mq.put("a");
mq.put("b");
mq.put("c");
mq.put("d");
mq.put("e");

System.out.println("当前容器的长度:" + mq.getSize());

Thread t1 = new Thread(() -> {
mq.put("f");
mq.put("g");
}, "t1");

t1.start();

Thread t2 = new Thread(() -> {
Object o1 = mq.take();
System.out.println("移除的元素为:" + o1);
Object o2 = mq.take();
System.out.println("移除的元素为:" + o2);
}, "t2");

try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}

t2.start();

}
}


 三、单例模式

1、double check instance

public class DubbleSingleton {

private volatile static DubbleSingleton ds;

// 1、私有构造方法
private DubbleSingleton() {
}

// 2、公共方法内部,双重校验
public static DubbleSingleton getDs() {
if (ds == null) {
try {
// 模拟初始化对象的准备时间...
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (DubbleSingleton.class) {
if (ds == null) {
ds = new DubbleSingleton();
}
}
}
return ds;
}

public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DubbleSingleton.getDs().hashCode());
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DubbleSingleton.getDs().hashCode());
}
}, "t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DubbleSingleton.getDs().hashCode());
}
}, "t3");

t1.start();
t2.start();
t3.start();
}

}

2、static inner class

public class Singletion {

private Singletion() {
}
private static class InnerSingletion {
private static Singletion single = new Singletion();
}
public static Singletion getInstance() {
return InnerSingletion.single;
}
}


举报

相关推荐

0 条评论