JavaSe基础XX15——线程_2
2014-08-25 10:12
337 查看
*08-多线程(线程的状态)
CPU的执行资格:可以被CPU处理但在处理队列排列
CPU的执行权:正在被CPU执行
*09-多线程(创建线程的第二种方式—实现Runnable接口)
类,类中的代码不止一个人要用。而且需要同时执行。这个时候就需要线程来实现。
但假如myThread有父类,就不能再继承Thread了。那该怎么办?
当一个类有父类的时候就不能再继承Thread的了。
不继承也有其他方法解决。——扩展Demo类的内容,实现多功能,接口。implement
*10-多线程(第二种方式的细节)
内部的设计思想
*11-多线程(第二种方式的好处)
实现Runnable接口的好处:
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。
按照面向对象的思想将任务的封装成对象。
2,避免了java单继承的局限性。
所以,创建线程的第二种方式较为常用。
*12-多线程(卖票示例)
写程序的步骤:
1)写需求
2)。。。
。。。。
*13-多线程(线程安全问题的现象)
我们分析上面这个程序的时候可以发现,存在一些情况。
运行的结果当中出现了这样的情况:
Thread-1...10
Thread-2...9
Thread-0...8
Thread-2...7
Thread-1...6
Thread-3...5
Thread-2...4
Thread-1...3
Thread-2...2
Thread-3...1
Thread-2...0
Thread-1...-1
Thread-0...-2
或者用thread.sleep(10)来进行停顿,看效果。
如何避免呢?
*14-多线程(线程安全问题产生的原因)
线程安全问题产生的原因:
1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条
*15-多线程(同步代码块)
解决思路;
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,
其他线程时不可以参与运算的。
必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中,用同步代码块就可以解决这个问题。
同步代码块的格式:
synchronized(对象)
{
需要被同步的代码 ;
}
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁。
完整代码:
*16-多线程(同步的好处和弊端)
加了synchronized 关键字之后,为什么就能保证其他线程进不来了呢?
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。效率低是在我们可承受范围之内。
同步的前提:同步中必须有多个线程并使用同一个锁。
*17-多线程(同步的前提)
同步的前提:同步中必须有多个线程并使用同一个锁。
*18-多线程(同步函数)
银行存款的例子。
同步代码块——用的锁是我们自己建立的obj
同步函数——的锁是什么呢?
都可以保证同步。
---------------------------------------
上面的代码会出现线程不安全的情况,结果的输出为:
-->sum:200
-->sum:200
-->sum:400
-->sum:500
-->sum:300
-->sum:600
方法1:
方法2:
*19-多线程(验证同步函数的锁)
验证同步代码块和同步函数使用的锁是不是同一个。
同步函数的锁是this。
同步函数的使用的锁是this;
同步函数和同步代码块的区别:
同步函数的锁是固定的this。
同步代码块的锁是任意的对象。
建议使用同步代码块。
举例:
上面的代码会有着两种结果输出:
①
②
结果就说明了两个不是同一个锁。
修改:
*20-多线程(验证静态同步函数的锁)
把num的值改为statci。
输出的结果不正确,说明了静态同步函数的锁不是this,原因很简单,因为静态函数没有this。
总结:
静态的同步函数使用的锁是 该函数所属字节码文件对象
可以用 getClass方法获取,也可以用当前 类名.class 表示。
*21-多线程(单例模式涉及的多线程问题)
在多线情况下,有没有安全隐患。
饿汉式没有,懒汉式有。
解决方式1;
但这样的话,就会降低效率。因为假如想取得一个实例,首先要判断锁,之后在判断是否为空。这个时候,我们可以对代码进行改写。
getClass是非静态的的。不能用做锁。
所以可以用这种双重判断来解决单例模式的效率和安全问题。
*22-多线程(死锁示例)
死锁的体现形式之一 —— 同步的嵌套。
什么是死锁,看下面的例子、
面试:请写出一个死锁程序。
*郁闷答疑——关于Obj放的位置
CPU的执行资格:可以被CPU处理但在处理队列排列
CPU的执行权:正在被CPU执行
*09-多线程(创建线程的第二种方式—实现Runnable接口)
类,类中的代码不止一个人要用。而且需要同时执行。这个时候就需要线程来实现。
package testThread; public class main { public static void main(String[] args) { myThread t1 = new myThread(); myThread t2 = new myThread(); t1.start(); t2.start(); } } class myThread extends Thread{ @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"..."+i); } } }
但假如myThread有父类,就不能再继承Thread了。那该怎么办?
当一个类有父类的时候就不能再继承Thread的了。
不继承也有其他方法解决。——扩展Demo类的内容,实现多功能,接口。implement
class Demo implements Runnable//extends Fu //准备扩展Demo类的功能,让其中的内容可以作为线程的任务执行。 //通过接口的形式完成。 { public void run() { show(); } public void show() { for(int x=0; x<20; x++) { System.out.println(Thread.currentThread().getName()+"....."+x); } } } class ThreadDemo { public static void main(String[] args) { Demo d = new Demo(); Thread t1 = new Thread(d); Thread t2 = new Thread(d); t1.start(); t2.start(); // Demo d1 = new Demo();<span style="white-space:pre"> </span>d1不是线程对象 // Demo d2 = new Demo(); // d1.start(); // d2.start(); } }
/* 创建线程的第一种方式:继承Thread类。 创建线程的第二种方式:实现Runnable接口。 1,定义类实现Runnable接口。 2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。 3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。 为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中。 所以要在线程对象创建时就必须明确要运行的任务。 4,调用线程对象的start方法开启线程。 实现Runnable接口的好处: 1,将线程的任务从线程的子类中分离出来,进行了单独的封装。 按照面向对象的思想将任务的封装成对象。 2,避免了java单继承的局限性。 所以,创建线程的第二种方式较为常用。 */
*10-多线程(第二种方式的细节)
内部的设计思想
class Thread { private Runnable r; Thread() { } Thread(Runnable r) { this.r = r; } public void run() { if(r!=null) r.run(); } public void start() { run(); } } class ThreadImpl implements Runnable { public void run() { System.out.println("runnable run"); } } ThreadImpl i = new ThreadImpl(); Thread t = new Thread(i); t.start(); class SubThread extends Thread { public void run() { System.out.println("hahah"); } } //SubThread s = new SubThread(); //s.start();
*11-多线程(第二种方式的好处)
实现Runnable接口的好处:
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。
按照面向对象的思想将任务的封装成对象。
2,避免了java单继承的局限性。
所以,创建线程的第二种方式较为常用。
*12-多线程(卖票示例)
写程序的步骤:
1)写需求
2)。。。
。。。。
package testThread; class Ticket implements Runnable { private int num = 100; @Override public void run() { while (num > 0) { System.out .println(Thread.currentThread().getName() + "..." + num--); } } } public class TicketDemo { public static void main(String[] args) { // TODO Auto-generated method stub Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }
*13-多线程(线程安全问题的现象)
我们分析上面这个程序的时候可以发现,存在一些情况。
package testThread; class Ticket implements Runnable { private int num = 10; @Override public void run() { while (num > 0) { for(int i = 0;i<999999;i++){} System.out .println(Thread.currentThread().getName() + "..." + num--); } } } public class TicketDemo { public static void main(String[] args) { // TODO Auto-generated method stub Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }
运行的结果当中出现了这样的情况:
Thread-1...10
Thread-2...9
Thread-0...8
Thread-2...7
Thread-1...6
Thread-3...5
Thread-2...4
Thread-1...3
Thread-2...2
Thread-3...1
Thread-2...0
Thread-1...-1
Thread-0...-2
或者用thread.sleep(10)来进行停顿,看效果。
如何避免呢?
*14-多线程(线程安全问题产生的原因)
线程安全问题产生的原因:
1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条
*15-多线程(同步代码块)
解决思路;
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,
其他线程时不可以参与运算的。
必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中,用同步代码块就可以解决这个问题。
同步代码块的格式:
synchronized(对象)
{
需要被同步的代码 ;
}
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁。
class Ticket implements Runnable//extends Thread { private int num = 100; Object obj = new Object(); public void run() { while(true) { synchronized(obj) { if(num>0) { try{Thread.sleep(10);}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....sale...."+num--); } } } } }
完整代码:
package testThread; class Ticket implements Runnable { private int num = 1000; Object obj = new Object(); @Override public void run() { while (num > 0) { synchronized (obj) { // try { // Thread.sleep(20); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(Thread.currentThread().getName() + "..." + num--); } } } } public class TicketDemo { public static void main(String[] args) { // TODO Auto-generated method stub Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }
*16-多线程(同步的好处和弊端)
加了synchronized 关键字之后,为什么就能保证其他线程进不来了呢?
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。效率低是在我们可承受范围之内。
同步的前提:同步中必须有多个线程并使用同一个锁。
*17-多线程(同步的前提)
同步的前提:同步中必须有多个线程并使用同一个锁。
*18-多线程(同步函数)
银行存款的例子。
/* 需求:储户,两个,每个都到银行存钱每次存100,,共存三次。 */ class Bank { private int sum; // private Object obj = new Object(); public synchronized void add(int num)//同步函数 { // synchronized(obj) // { sum = sum + num; // --> try{Thread.sleep(10);}catch(InterruptedException e){} System.out.println("sum="+sum); // } } } class Cus implements Runnable { private Bank b = new Bank(); public void run() { for(int x=0; x<3; x++) { b.add(100); } } } class BankDemo { public static void main(String[] args) { Cus c = new Cus(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
同步代码块——用的锁是我们自己建立的obj
同步函数——的锁是什么呢?
都可以保证同步。
---------------------------------------
package testThread; class Bank { private int sum; public void add(int num) { sum = num + sum; System.out.println("-->sum:" + sum); } } class Person implements Runnable { Bank b = new Bank(); @Override public void run() { for (int i = 0; i < 3; i++) { b.add(100); } } } public class BankDemo { public static void main(String[] args) { Person p = new Person(); Thread t1 = new Thread(p); Thread t2 = new Thread(p); t1.start(); t2.start(); } }
上面的代码会出现线程不安全的情况,结果的输出为:
-->sum:200
-->sum:200
-->sum:400
-->sum:500
-->sum:300
-->sum:600
方法1:
package testThread; class Bank { private int sum; private Object obj = new Object(); public void add(int num) { // 方法一,在下面的语句添加syncni关键字 synchronized (obj) { sum = num + sum; System.out.println("-->sum:" + sum); } } } class Person implements Runnable { Bank b = new Bank(); @Override public void run() { for (int i = 0; i < 3; i++) { b.add(100); } } } public class BankDemo { public static void main(String[] args) { Person p = new Person(); Thread t1 = new Thread(p); Thread t2 = new Thread(p); t1.start(); t2.start(); } }
方法2:
package testThread; class Bank { private int sum; public synchronized void add(int num) {// 方法二,同步函数 sum = num + sum; System.out.println("-->sum:" + sum); } } class Person implements Runnable { Bank b = new Bank(); @Override public void run() { for (int i = 0; i < 3; i++) { b.add(100); } } } public class BankDemo { public static void main(String[] args) { Person p = new Person(); Thread t1 = new Thread(p); Thread t2 = new Thread(p); t1.start(); t2.start(); } }
*19-多线程(验证同步函数的锁)
验证同步代码块和同步函数使用的锁是不是同一个。
同步函数的锁是this。
同步函数的使用的锁是this;
同步函数和同步代码块的区别:
同步函数的锁是固定的this。
同步代码块的锁是任意的对象。
建议使用同步代码块。
举例:
package testThread; class Ticket implements Runnable { private int num = 100; boolean flag = true; Object obj = new Object(); @Override public void run() { if (flag) while (true) { synchronized (obj) { if (num > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "...obj..." + num--); } } } else while (true) { show(); } } public synchronized void show() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } if (num > 0) System.out.println(Thread.currentThread().getName() + "...func..." + num--); } } public class TicketDemo { public static void main(String[] args) { // TODO Auto-generated method stub Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } t.flag = false; t2.start(); } }
上面的代码会有着两种结果输出:
①
②
结果就说明了两个不是同一个锁。
修改:
if (flag) while (true) { synchronized (this) { if (num > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "...obj..." + num--); } } } else while (true) { show(); }
*20-多线程(验证静态同步函数的锁)
把num的值改为statci。
输出的结果不正确,说明了静态同步函数的锁不是this,原因很简单,因为静态函数没有this。
/* 静态的同步函数使用的锁是 该函数所属字节码文件对象 可以用 getClass方法获取,也可以用当前 类名.class 表示。 */ class Ticket implements Runnable { private static int num = 100; // Object obj = new Object(); boolean flag = true; public void run() { // System.out.println("this:"+this.getClass()); if(flag) while(true) { synchronized(Ticket.class)//(this.getClass()) { if(num>0) { try{Thread.sleep(10);}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....obj...."+num--); } } } else while(true) this.show(); } public static synchronized void show() { if(num>0) { try{Thread.sleep(10);}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....function...."+num--); } } } class StaticSynFunctionLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); // Class clazz = t.getClass(); // // Class clazz = Ticket.class; // System.out.println("t:"+t.getClass()); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(InterruptedException e){} t.flag = false; t2.start(); } }
总结:
静态的同步函数使用的锁是 该函数所属字节码文件对象
可以用 getClass方法获取,也可以用当前 类名.class 表示。
*21-多线程(单例模式涉及的多线程问题)
/* 多线程下的单例 */ //饿汉式 class Single { private static final Single s = new Single(); private Single(){} public static Single getInstance() { return s; } }
class Single { private static Single s = null; private Single(){} public static Single getInstance() { if(s==null) { synchronized(Single.class) { if(s==null) // -->0 -->1 s = new Single(); } } return s; } }
在多线情况下,有没有安全隐患。
饿汉式没有,懒汉式有。
解决方式1;
但这样的话,就会降低效率。因为假如想取得一个实例,首先要判断锁,之后在判断是否为空。这个时候,我们可以对代码进行改写。
getClass是非静态的的。不能用做锁。
所以可以用这种双重判断来解决单例模式的效率和安全问题。
*22-多线程(死锁示例)
死锁的体现形式之一 —— 同步的嵌套。
什么是死锁,看下面的例子、
/* 死锁:常见情景之一:同步的嵌套。 */ class Ticket implements Runnable { private int num = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) while(true) { synchronized(obj) { show(); } } else while(true) this.show(); } public synchronized void show() { synchronized(obj) { if(num>0) { try{Thread.sleep(10);}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....sale...."+num--); } } } } class DeadLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); // System.out.println("t:"+t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(InterruptedException e){} t.flag = false; t2.start(); } }
面试:请写出一个死锁程序。
class Test implements Runnable { private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName()+"..if locka...."); synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"..if lockb...."); } } } else { while(true) synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"..else lockb...."); synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName()+"..else locka...."); } } } } } class MyLock { public static final Object locka = new Object(); public static final Object lockb = new Object(); } class DeadLockTest { public static void main(String[] args) { Test a = new Test(true); Test b = new Test(false); Thread t1 = new Thread(a); Thread t2 = new Thread(b); t1.start(); t2.start(); } }
*郁闷答疑——关于Obj放的位置
相关文章推荐
- JavaSe基础XX15——线程_1
- JavaSe基础XX15——线程_3
- 黑马程序员_JavaSE基础15 之 常用对象API String类 SringBuffer类
- JavaSe基础XX01——函数
- JavaSe基础XX16——API对象-基本数据类型对象包装类
- JavaSe基础XX16——API对象-StringBuffer类
- 黑马程序员_JavaSE基础13 之 线程创建 线程安全 同步代码块
- JavaSe基础XX17——常用对象API-集合框架_4
- JavaSe基础XX16——Eclipse使用
- JavaSe基础XX14——包
- JavaSe基础XX17——常用对象API-集合框架_2
- JavaSe基础XX02——数组
- JavaSe基础XX07——面向对象
- JavaSe基础XX06——面向对象
- JavaSe基础XX14——习题解答_2
- JavaSe基础XX12——面向对象——[异常_1]
- JavaSE 拾遗(15)——JavaSE 高新技术基础增强...java5简单新特性和枚举
- JavaSe基础XX05——面向对象
- JavaSe基础XX09——面向对象
- JavaSe基础XX16——API对象-String