当前位置: 首页 > article >正文

多线程编程java_java多线程编程

1. 多线程编程

d02310122fbad7dc28f2bd8b4a2a48dc.png

2. Thread和Runnable

java中实现多线程的方式有两种,继承Thread类、实现Runnable接口

2.1 Thread

开发人员可以编写一个类继承Thread,并重写run方法,在run方法里面编写线程将要执行的代码。

创建线程对象后,只需要调用start()方法即可让线程进入就绪队列,等待操作系统调度。

需要特别注意的是调度具有随机性和随时性。也就是说无法确定下一次调度哪个线程,也无法确定什么时刻进行调度

public classMyThreadTest {public static voidmain(String[] args) {

MyThread myThread= newMyThread();

myThread.start();//把myThread加入到就绪队列里面

}

}class MyThread extendsThread {

@Overridepublic voidrun() {

System.out.println("MyThread执行了");

}

}

2.2 Runnable

除了继承Thread重写run方法外,在简单的情况下,还可通过实现Runnable接口的方式编写线程执行的代码

Thread thread = new Thread(newRunnable() {

@Overridepublic voidrun() {

System.out.println("Runnable接口方式实现多线程");

}

});

3.线程安全问题

一个数据,如一个对象或对象中的某个字段,如果有多个线程可以同时访问它,就可能会出现线程安全问题:数据错乱、程序出错或其他无法预知的问题

比如线程1要遍历一个list,线程2要把这个list清空,如果这两个线程同时执行就可能会出现线程安全问题

public classThreadQuestionTest {public static voidmain(String[] args) {

List list = new ArrayList();for (int i = 0; i < 100000; i++) {

list.add(i);

}

Thread thread1= new Thread(newRunnable() {

@Overridepublic voidrun() {for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

}

});

Thread thread2= new Thread(newRunnable() {

@Overridepublic voidrun() {

list.clear();

}

});

thread1.start();

thread2.start();

}

}

输出:

0

null

null

null

null

...

4. 线程同步

线程同步控制,即使用某种方式使得一个线程在操作完某个数据前,别的线程无法操作这个数据,从而避免多个线程同时操作一个数据,进而避免线程安全问题

线程同步控制的方式有同步锁机制、等待/通知机制、信号量机制等,它们应用在不同复杂度的场景下

4.1同步代码块

synchronized同步锁机制

Java中每个对象都有一把锁,同一时刻只能有一个线程持有这把锁。线程可以使用synchronized关键字向系统申请某个对象的锁,得到锁之后,别的线程再申请该锁时,就只能等待。持有锁的线程在这次操作完成后,可以释放锁,以便其他线程可以获得锁

synchronized有两种形式,synchronized代码块和synchronized方法

synchronized代码块,又称同步代码块:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classSynchronizedBlockTest {public static voidmain(String[] args) {

List list = new ArrayList();for (int i = 0; i < 100000; i++) {

list.add(i);

}

Thread thread1= new Thread(newRunnable() {

@Overridepublic voidrun() {synchronized(list) {for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

}

}

});

Thread thread2= new Thread(newRunnable() {

@Overridepublic voidrun() {synchronized(list) {

list.clear();

}

}

});

thread1.start();

thread2.start();

}

}

View Code

4.2 同步方法

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classSynchronizedMethodTest {public static voidmain(String[] args) {

Data data= newData();

Thread thread1= new Thread(newRunnable() {

@Overridepublic voidrun() {

data.bianliList();

}

});

Thread thread2= new Thread(newRunnable() {

@Overridepublic voidrun() {

data.clearList();

}

});

thread1.start();

thread2.start();

}

}classData {private Listlist;publicData() {

list= new ArrayList();for (int i = 0; i < 100000; i++) {

list.add(i);

}

}public synchronized voidbianliList() {for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

}public synchronized voidclearList() {

list.clear();

}

}

View Code

非静态同步方法申请的锁是类的当前对象的锁,静态同步方法申请的锁是类的Class对象的锁。同步方法执行完后即向系统归还锁

synchronized代码块和synchronized方法的效果一样,可根据具体场景灵活选用

对于简单的需要线程同步控制的应用场景,synchronized基本够用

但需要注意,所有需要同步的线程必须都申请同一个对象的锁,当申请不同的锁或者有的线程没有使用synchronized时,同步锁机制就会失效

5. wait/notify 等待/通知机制

对于稍复杂的情况,比如多个线程需要相互合作有规律的访问共享数据,就可以使用wait/notify机制,即等待/通知机制,也称等待/唤醒机制

等待/通知机制建立在synchronized同步锁机制的基础上,即在同步代码块(或同步方法)内,如果当前线程执行了lockObject.wait()(lockObject表示提供锁的对象),则当前线程立即暂停执行,并被放入阻塞队列,并向系统归还所持有的锁,并在lockObject上等待,直到别的线程调用lockObject.notify()

如果有多个线程在同一个对象上等待,notify()方法只会随机通知一个等待的线程,也可以使用notifyAll()方法通知所有等待的线程。被通知的线程获得锁后会进入就绪队列

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classWaitNotifyTest {public static voidmain(String[] args) {

Object lockObject= newObject();

Thread thread1= new Thread(newRunnable() {

@Overridepublic voidrun() {synchronized(lockObject) {try{

System.out.println("线程1即将开始在lockObject上等待");

lockObject.wait();

System.out.println("线程1收到通知并获得锁,开始继续执行");

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

});

Thread thread2= new Thread(newRunnable() {

@Overridepublic voidrun() {synchronized(lockObject) {

System.out.println("线程2将随机通知在lockObject上等待的线程");

lockObject.notify();

}

}

});

thread2.start();

thread1.start();

}

}

View Code

5.1 wait/notify-生产者消费者实例

一个很典型的生产者消费者例子:现有一个生产者、一个消费者、10个盘子(缓冲区),生产者把生产的产品放入空盘子中,当没有空盘子时就停止生产;消费者消费盘子中的产品,当所有的盘子都是空盘子时就停止消费

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classProducerConsumerTest{public static voidmain(String[] args) {

List buffer = new LinkedList();int maxSize = 10;

Producer producer= newProducer(buffer, maxSize);

Consumer consumer= newConsumer(buffer);

producer.start();

consumer.start();

}

}//模拟生产者

class Producer extendsThread {private List buffer; //缓冲区,表示多个盘子

private int maxSize; //表示盘子个数

public Producer(List buffer, intmaxSize) {this.buffer =buffer;this.maxSize =maxSize;

}

@Overridepublic voidrun() {int id = 0;while (true) {synchronized(buffer) {if (buffer.size() < maxSize) {//有空盘子则继续生产

id++;//表示生产了一个产品

buffer.add(id); //表示把产品放入一个空盘子中

System.out.println("生产产品" + id + "并通知消费者可以消费了");

buffer.notify();//通知消费者有产品可以消费了

} else{//如果没有空盘子则等待

System.out.println("没有空盘子了,生产者停止生产产品");try{

buffer.wait();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

}//模拟消费者

class Consumer extendsThread {private List buffer; //缓冲区,表示多个盘子

public Consumer(Listbuffer) {this.buffer =buffer;

}

@Overridepublic voidrun() {while (true) {synchronized(buffer) {if (buffer.size() > 0) { //有不空的盘子

int id = buffer.remove(0); //表示消费了一个产品

System.out.println("消费产品" + id + "并通知生产者有空盘了");

buffer.notify();

}else{//全部都是空盘子则等待

System.out.println("全部都是空盘子,消费者停止消费产品");try{

buffer.wait();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

}

View Code

http://www.lryc.cn/news/2416574.html

相关文章:

  • 递归调用栈溢出问题分析与解决
  • C#的Winform多语言实现(resx文件)
  • 电脑时间老是重置?一招教你轻松解决!
  • 黑色主题个人主页HTML源码
  • 印度电影推荐
  • 教您如何使用WebMatrix创建第一个网页
  • 网络安全笔记-信息安全工程师与网络安全工程师考试大纲(附:Web安全大纲)
  • Windows xp正版验证序列号大全
  • 如何利用CSDN资源来建立技术社区 - 博客篇
  • Farpoint使用一点小总结
  • NSTimer介绍
  • 【C语言深度剖析】深入理解C语言中的移位操作符(代码+图解)
  • 群体智能优化算法之人工鱼群优化算法(Artificial Fish Swarm Algorithm,AFSA)
  • 视频下载网址
  • 为用户“NT AUTHORITY/NETWORK SERVICE”授予的权限不足,无法执行此操作。 (rsAccessDenied)
  • OMG Data Distribution Service(DDS)规范解读-Part2
  • 2020最新Spring框架教程【IDEA版】-Spring框架从入门到精通
  • TC流量控制
  • 2023最新PHP短网址短链接生成源码
  • NOIP2022 喵了个喵
  • Android AOSP LatinIME输入法自定义图片按钮
  • ExitProcess,TerminateProcess,CreateToolhelp32Snapshot,Process32First,Process32Next,OpenProcess
  • windows进程 windows多进程编程
  • JavaScript之表单验证
  • 从零开始了解《间之楔动漫》:带你领略这部作品的独特魅力!
  • 光盘加密大师轻松为光盘加密
  • 一个简单的TODO,原来这么好用
  • a标签href属性的用法
  • #python学习笔记(五)#循环语句
  • 微信小程序毕业设计-网上商城系统项目开发实例(附源码+演示视频+LW)