2017年6月30日 上午10:31
多线程的好处:
解决了多部分代码同时运行的情况
坏处:
每个线程占的资源少,单个线程的效率比较低
实现
1. 继承Thread
1. run()运行代码
2. start()开启线程:没有开始运行,进入了
3. 一个线程类对象只能调用一次start()方法

图1 线程的四种状态(五种:创建,就绪,运行,阻塞,停止)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package package1;
public class ThreadTest extends Thread{ private String name; private int num = 5; public ThreadTest(String name){ this.name = name ; } public void run(){ while(num != 0){ System.out.println(name+"\t"+num--); } } public static void main(String[] args) { ThreadTest tt = new ThreadTest("线程1"); ThreadTest tt1 = new ThreadTest("线程2"); tt.start(); tt1.start(); } }
|
输出:

2. 接口Runnable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package package1;
public class RunnableTest implements Runnable{ private String name ; private int num =10; public RunnableTest(String name) { super(); this.name = name; }
public static void main(String[] args) { RunnableTest rt = new RunnableTest("线程1"); new Thread(rt).start(); new Thread(rt).start(); }
@Override public void run() { while(num != 0){ System.out.println(name+"\t"+num--); } }
}
|
输出1

输出2

对比 输出1 和 输出2 发现:
1. 输出1 一共输出的为11个,10输出了两次
2. 输出2 一共输出了10个,1-10各一次
总结:会有特殊情况出现
对比 程序1 和 程序2 发现:
1. 实现Runnable接口,方便实现资源共享
2. 继承Thread类受单继承影响,不适合多线程共享资源
3. 只有Thread才能创建线程对象,Runnable只是实现run()方法
4. **多线程的特点是:**
1. 一个对象的run()可以同时执行
2. 多个对象的run()方法也可以同时执行

图2:Thread实现方式
Thread 的角色:提供资源 + 提供方法 + 运行方法

图3:Runnable实现方式
RunnableTest的角色:提供资源 + 提供方法run
Thread的角色:调用run
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package package1;
public class ThreadTest extends Thread{ private String name; private int num = 5; public ThreadTest(String name){ this.name = name ; } public void run(){ while(num != 0){ System.out.println(name+"\t"+num--); } } public static void main(String[] args) { ThreadTest tt = new ThreadTest("线程1"); tt.start(); tt.start(); } }
|
输出:

通过这个例子来理解Runnable 和 Thread的不同:
1. Thread的run方法不能让同一个对象同时调用进行,但,可以不同对象之间进行
2. Runnable 的run方法可以被同一个对象同时调用
3. 那么,在thread中,如果强制调用tt.start()两次,就类似于runnable调用两次start(),会发生什么呢?很可惜,因为start()方法是synchronized的(如图5),所以只能支持Runnable的两次(图7),不支持Thread的两次(图6)。

图5

图6

图7
Thread的方法:
- Static Thread currentThread()
- Final String getName()
- Final void setPriority();设置优先级
- Void start()
- Static void sleep() 让出执行权,不让出资源
- Final void yield()暂停当前线程,让其他线程(大家同一个起跑线) 礼让
- void run()执行线程
线程方法 + object方法

同步的前提:
- 两个或两个以上的线程
- 多个线程使用同一资源
- (必须用Runnable)或者 (Thread+ static资源变量)
同步的概念:
- 回去判断每个线程上的锁,浪费资源
- 同一个时间只能运行一个线程
- 同步可以解决线程中的安全问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package package1;
public class ThreadTest2 extends Thread { private String name ; public ThreadTest2(String name) { this.name = name; } public static void main(String[] args) { ThreadTest2 tt = new ThreadTest2("线程"); tt.start(); } @Override public void run(){ for(int i = 0 ;i < 4;i++){ System.out.println(i); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
} } }
|
以上代码使用
1. Thread.currentThread ().sleep 实现休眠
2. Thread.currentThread().yield() 实现礼让
同步代码块 同步方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package package1;
public class RunnableTest2 implements Runnable { private int num = 10 ; @Override public void run() { while(num != 0){ synchronized (RunnableTest2.class) { if(num > 0){ System.out.println(Thread.currentThread().getName()+"\t"+num--); } }
} } public synchronized void sail(){ if(num > 0){ System.out.println(Thread.currentThread().getName()+"\t"+num--); } } public static void main(String[] args) { RunnableTest2 rt = new RunnableTest2(); new Thread(rt).start(); new Thread(rt).start(); new Thread(rt).start(); new Thread(rt).start(); } }
|
同步代码块 同步方法的区别:
1. 上面的代码包含的两种方法,通过注释来更换
2. 他们两种没有功能上的区别,可以相互替换
3. 写成方法可以更加灵活,因为可以分块写,不用写成一块了
同步的死锁:

理解:
1. 爸:我要你的成绩单
2. 儿:我要玩具
3. 爸:你先给我成绩单!
4. 儿:不!你先给我玩具!
5. 两个人怒目相对,谁都不给谁,就相互看着…….
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package package1;
public class LockRunnable implements Runnable { private int flag = 1;
static Object o1 = new Object(); static Object o2 = new Object(); @Override public void run() { System.out.println(flag); if(flag == 1){ synchronized (o1) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o2) { System.out.println("可以给你玩具了"); } } } if(flag == 0){ synchronized (o2) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o1) { System.out.println("可以给成绩单"); } } } }
public static void main(String[] args) { LockRunnable t1 = new LockRunnable(); t1.flag =1 ; LockRunnable t2 = new LockRunnable(); t2.flag =0 ; new Thread(t1).start(); new Thread(t2).start(); }
}
|
在上面的代码中注意:
1. 正确理解synchronize的意思:
1. **用在方法时,这个方法不能被同一个对象同时调用**
2. 用在块时,()里的为需要站用的资源,根据这个进行判断
2. 为什么要使用static
3. 注意这里产生了两个LockRunnable资源对象,一个代表父亲,一个代表儿子