Java线程(一):传统线程的实现、互斥与通信
2014-11-08 13:34
696 查看
一、实现多线程:
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
1、继承Thread类
2、实现Runable接口
——建议使用接口
运行:一个Thread对象就有一个线程
二、线程互斥:synchronized
1、概述:
1)、线程安全问题,简单理解可以用银行转账来解释。
2)、传统线程互斥,使用 synchronized
关键字。
3)、synchronized() 代码块:
①、synchronized(对象) 代码块需要锁定同一个对象,一般会锁定业务类对象,即synchronized(this)即可。
②、如静态方法互斥,则需要锁定内存中的字节码对象,即synchronized(XXX.class)。
③、synchronized
方法锁定的也是对象。
4)、synchronized 方法:一个方法只有一个synchronized
,不然容易产生死锁。
2、实现
注意点一:静态方法不能创建内部类实例对象
1)、原因:
①、内部类可以访问外部类的成员变量;
②、成员变量是在对象创建后才分配空间的;
③、静态方法中可以不创建对象即访问对象的方法。
2)、实例分析:Outputer是内部类,可以访问外部类的成员变量,即一定有了外部类的实例对象,但是在main方法中根本不需要创建外部类对象,就矛盾了。
注意点二:线程调用的必须是同一个对象。
1)、如线程中每次都new Outputer()然后再去调用方法,那么synchronized(this)
和synchronized 方法是实现不了互斥的。
2)、但是这种情况下
锁定字节码是可以是实现的。其实由于字节码的唯一性,任何时候锁定字节码都是可以实现互斥的。
3)、具体使用哪一种需要根据实际对象,但是一般我们不推荐锁定字节码而是使用同一个对象。
互斥代码如下:线程方法在通信中得到改善。
三、线程通信
1、关键字:wait、notify、一个boolean类型参数。
2、通过一个简单的案例实现线程通信:两个线程,子线程循环10次,主线程循环30次,然后子线程又循环10次,主线程30次,如此一共循环20次。
3、线程同步与互斥:
互斥、同步不是写在线程上,而是写在线程访问的资源上。
4、使用while()代替if(),这样会多检查一次参数,更加健壮。
5、synchronized(对象)
与 对象.wait 必须为同一个,不然会报错。
线程同步实现的代码如下:
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
1、继承Thread类
/** * * TraditionThread.java * * @title 继承Thread * @description * @author SAM-SHO * @Date 2014-11-8 */ class ExThread extends Thread { @Override public void run() { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("0:" + Thread.currentThread().getName()); } } }
2、实现Runable接口
——建议使用接口
/** * * TraditionThread.java * * @title 实现 Runnable 接口 * @description * @author SAM-SHO * @Date 2014-11-8 */ class RunThread implements Runnable { @Override public void run() { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("1:" + Thread.currentThread().getName()); } } }
运行:一个Thread对象就有一个线程
// 线程一 ExThread tThread1 = new ExThread(); tThread1.start(); // 线程二 Thread tThread2 = new Thread(new RunThread()); tThread2.start();【结果】:
0:Thread-0 1:Thread-1 0:Thread-0 1:Thread-1 0:Thread-0 1:Thread-1 .......
二、线程互斥:synchronized
1、概述:
1)、线程安全问题,简单理解可以用银行转账来解释。
2)、传统线程互斥,使用 synchronized
关键字。
3)、synchronized() 代码块:
①、synchronized(对象) 代码块需要锁定同一个对象,一般会锁定业务类对象,即synchronized(this)即可。
②、如静态方法互斥,则需要锁定内存中的字节码对象,即synchronized(XXX.class)。
③、synchronized
方法锁定的也是对象。
4)、synchronized 方法:一个方法只有一个synchronized
,不然容易产生死锁。
2、实现
注意点一:静态方法不能创建内部类实例对象
1)、原因:
①、内部类可以访问外部类的成员变量;
②、成员变量是在对象创建后才分配空间的;
③、静态方法中可以不创建对象即访问对象的方法。
2)、实例分析:Outputer是内部类,可以访问外部类的成员变量,即一定有了外部类的实例对象,但是在main方法中根本不需要创建外部类对象,就矛盾了。
注意点二:线程调用的必须是同一个对象。
1)、如线程中每次都new Outputer()然后再去调用方法,那么synchronized(this)
和synchronized 方法是实现不了互斥的。
2)、但是这种情况下
锁定字节码是可以是实现的。其实由于字节码的唯一性,任何时候锁定字节码都是可以实现互斥的。
3)、具体使用哪一种需要根据实际对象,但是一般我们不推荐锁定字节码而是使用同一个对象。
互斥代码如下:线程方法在通信中得到改善。
package com.Thread; /** * * TraditionalThreadSynchronized.java * * @title 传统线程互斥 * @description * @author SAM-SHO * @Date 2014-8-17 */ public class TraditionalThreadSynchronized { /** * @param args */ public static void main(String[] args) { // 静态方法不能创建内部类实例对象 // 原因: 内部类可以访问外部类的成员变量;成员变量是在对象创建后才分配空间的;静态方法中可以不创建对象即访问对象的方法。 // 如 // Outputer是内部类,可以访问外部类的成员变量,即一定有了外部类的实例对象,但是在main方法中根本不需要创建外部类对象,就矛盾了。 // FirstThread c = new FirstThread(); TraditionalThreadSynchronized tThreadSynchronized = new TraditionalThreadSynchronized(); tThreadSynchronized.init(); } /** * 定义初始化方法, 解决main(静态)方法不能创建内部类实例对象 */ public void init() { // 线程一 FirstThread firstThread = new FirstThread(); firstThread.start(); // 线程二 SecondThread secondThread = new SecondThread(); secondThread.start(); } /* * 线程一 */ class FirstThread extends Thread { Outputer out = new Outputer();//new 以后就是两个对象,使用this是锁不住的 @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } out.output2("ShaoXiaoBao"); } } } /* * 线程二 */ class SecondThread extends Thread { Outputer out = new Outputer(); @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } out.output2("ZhaoXiaoNiu"); } } } /** * * Outputer.java * * @title 内部类实现输出,业务类 * @description output方法要实现原子性 * * @author SAM-SHO * @Date 2014-8-17 */ class Outputer { // 使用synchronized 代码块 // synchronized(对象) 代码块需要锁定同一个对象, // 这边如果synchronized (name)就不行,一定要 Outputer对象 // output() 和 output1() 方法也是互斥的 public void output(String name) { int len = name.length(); synchronized (this) {//this就是Outputer这个对象 for (int i = 0; i < len; i++) { System.out.print(name.charAt(i)); } System.out.println(); } } /** * synchronized 方法 * 其实锁定的也是Outputer 对象 * @param name */ public synchronized void output1(String name) { int len = name.length(); for (int i = 0; i < len; i++) { System.out.print(name.charAt(i)); } System.out.println(); } /** * 如果有静态方法 a(),output2()与之需要互斥, * 则可以锁定该类字节码 * @param name */ public void output2(String name) { int len = name.length(); synchronized (Outputer.class) {// 解决与静态方法的互斥,使用字节码对象 for (int i = 0; i < len; i++) { System.out.print(name.charAt(i)); } System.out.println(); } } } }
三、线程通信
1、关键字:wait、notify、一个boolean类型参数。
2、通过一个简单的案例实现线程通信:两个线程,子线程循环10次,主线程循环30次,然后子线程又循环10次,主线程30次,如此一共循环20次。
3、线程同步与互斥:
互斥、同步不是写在线程上,而是写在线程访问的资源上。
4、使用while()代替if(),这样会多检查一次参数,更加健壮。
5、synchronized(对象)
与 对象.wait 必须为同一个,不然会报错。
线程同步实现的代码如下:
package com.Thread; /** * * TranditionalThreadComunication.java * * @title 线程同步与互斥: 互斥、同步不是写在线程上,而是写在线程访问的资源上。 * @description * @author SAM-SHO * @Date 2014-8-17 */ public class TranditionalThreadComunication { /** * @param args */ public static void main(String[] args) { TranditionalThreadComunication tThreadComunication = new TranditionalThreadComunication(); tThreadComunication.init(); } /** * 定义初始化方法, * 解决main(静态)方法不能创建内部类实例对象 */ public void init() { //保证两个线程访问同一个资源对象 Bussiness tBussiness = new Bussiness(); ChildThread childThread = new ChildThread(tBussiness);//子线程 MainThread mainThread = new MainThread(tBussiness);//主线程 childThread.start(); mainThread.start(); } /* * 子线程 */ class ChildThread extends Thread { private Bussiness tBussiness; public ChildThread(Bussiness tBussiness) { this.tBussiness = tBussiness; } @Override public void run() { for (int i = 0; i <= 20; i++) { tBussiness.eachChild(i); } } } /* * 主线程 */ class MainThread extends Thread { private Bussiness tBussiness; public MainThread(Bussiness tBussiness) { this.tBussiness = tBussiness; } @Override public void run() { for (int i = 0; i <= 20; i++) { tBussiness.eachMain(i); } } } /** * * Bussiness * * @title 业务实现类 * @description 用到的共同数据的若干方法应该设计在一个类身上 * * @author SAM-SHO * @Date 2014-8-17 */ class Bussiness { private boolean bShouldSub = true; /* * 循环10次的方法 * if 可以用 while代替 */ public synchronized void eachChild(int index) { while(!bShouldSub) {//一开始是true,那么就是执行循环 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i <= 10; i++) { System.out.println("子 线程-- "+i+ ", 第"+index+"循环"); } bShouldSub = false; this.notify();//唤醒主线程 } /* * 循环50次的方法 * if 可以用 while代替 */ public synchronized void eachMain(int index) { while(bShouldSub) {//一开始是true,那么就会wait try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i <= 30; i++) { System.out.println("主 线程---- "+i + ", 第"+index+"循环"); } bShouldSub = true; this.notify();//唤醒子线程 } } }
相关文章推荐
- Java多线程通信-利用传统的线程通信wait(),notify()方法实现“生产者消费者模式”
- ZeroMQ(java)之I/O线程的实现与组件间的通信
- java5 Condition用法--实现线程间的通信
- java中传统的线程通信个人见解
- Java多线程与并发应用-(3)-传统线程通信技术及生产者消费者模式
- java网络编程-双线程实现UDP通信
- Java线程间通信-回调的实现方式
- 12-使用java5条件阻塞condition实现线程间通信-实现线程间通信方式(2)
- Java线程间通信-回调的实现方式
- 18-java5阻塞队列实现线程间通信-实现线程间通信方式(3)
- Java线程间通信-回调的实现方式
- java基础——多线程(线程的同步互斥与通信)
- 【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明
- Java线程间通信-回调的实现方式
- java同步和互斥 : 线程之间通信
- java中传统的线程通信个人见解
- java学习——如何实现线程之间的通信 ,Condition 的使用
- Java传统多线程的实现有两种方法,继承Thread类或者实现Runnable即可.线程启动时调用start()方法.
- 黑马程序员——JAVA基础---线程之间的通信实现交替输出打印
- Java线程间通信-回调的实现方式