多线程
1 //java基础视频教程第11天-01-多线程 2 /* 3 进程和线程: 4 线程是程序中的控制单元或者叫执行路径 5 进程就是正在执行的程序,程序执行有执行顺序,这个执行顺序就是一个执行路程,或者叫做一个控制单元,程序运行都会在内存中开辟一段空间,都会分配一个地址,进程就是用来标识,定义这个空间的,用于封装里面的控制单元,线程是一个独立的控制单元 6 一个进程中至少有一个线程 7 8 举例:JVM执行时就有一个进程java.exe 9 这个进程至少有一个线程在执行,而且该线程运行在main函数中我们称之为主线程 10 其实JVM进程不止一个线程,JVM程序中还会有垃圾回收机制 11 12 多线程的意义: 13 提高了程序的效率 14 */ 15 class ThreadDemo 16 { 17 public static void main(String[] args) 18 { 19 for (long x=0;x<30000 ;x++ ) 20 { 21 System.out.print(x); 22 } 23 } 24 }
1 //java基础视频教程第11天-02-多线程(创建线程-继承Thread类) 2 /* 3 自定义线程 4 首先是JVM调用系统资源来完成进程的建立和线程的建立(thread) 5 建立一个进程有三个步骤: 6 1.建立类并继承Thread 7 2.复写Thread的run方法 8 3.创建一个进程(对象),并启用start()方法,start()方法的作用有两个,一个是启动线程,一个是调用jvm去执行run方法 9 */ 10 class Demo extends Thread //建立线程必须继承Thread 11 { 12 public void run() 13 { 14 for (int x=0;x<80 ;x++) 15 { 16 System.out.println("Demo run---"+x); 17 } 18 } 19 } 20 class ThreadDemo1 21 { 22 public static void main(String[] args) //此处有个图例,解释多线程 23 { 24 Demo d = new Demo(); //创建一个线程 25 d.start(); //start()方法有两个作用,一是启动线程,二是调用JVM去执行run方法 26 27 for (int x=0;x<80 ;x++) 28 { 29 System.out.println("Hello word---"+x); 30 } 31 } 32 } //发现每次运行结果都不一样,为什么不一样呢?因为在多线程之间,CUP在做着高速切换指令,但是又是什么导致CPU出现随机切换呢?优化资源 33 //所以在单核CPU时,同一时刻只能有一个进程在执行 34 35
1 //java基础视频教程第11天-03-多线程(创建线程-run和start特点) 2 /* 3 自定义线程 4 首先是JVM调用系统资源来完成进程的建立和线程的建立(thread) 5 建立一个进程有三个步骤: 6 1.建立类并继承Thread 7 2.复写Thread的run方法 8 为什么要复写run方法,因为run方法里面放的是线程要执行的代码,而Thread的run方法是一个空,复写父类的run方法,并调用start方法启动线程和调用jvm去执行run方法 9 3.创建一个进程(对象),并启用start()方法,start()方法的作用有两个,一个是启动线程,一个是调用jvm去执行run方法 10 */ 11 class Demo extends Thread //建立线程必须继承Thread 12 { 13 public void run() 14 { 15 for (int x=0;x<80 ;x++) 16 { 17 System.out.println("Demo run---"+x); 18 } 19 } 20 } 21 class ThreadDemo2 22 { 23 public static void main(String[] args) //此处有个图例,解释多线程 24 { 25 Demo d = new Demo(); //创建一个线程 26 d.start(); //start()方法有两个作用,一是启动线程,二是调用JVM去执行run方法 27 //d.run(); //如果直接写d.run();其实这是对象调用run方法,而非调用JVM去执行run()方法,这里创建了线程但是没有启动,也就是说这个是主线程在执行。 28 Thread t = new Thread(); 29 t.start(); //Thread的run方法是一个空 30 for (int x=0;x<80 ;x++) 31 { 32 System.out.println("Hello word---"+x); 33 } 34 } 35 } 36
1 //java基础教程第11天-04-多线程(线程练习) 2 /* 3 需求:多个线程与主线程交替运行 4 */ 5 class Test extends Thread 6 { 7 private String name; 8 Test(String name) 9 { 10 this.name = name; 11 } 12 public void run() 13 { 14 for (int x=0;x<60 ;x++ ) 15 { 16 System.out.println(name+"---run---"+x); 17 } 18 } 19 } 20 class ThreadTest 21 { 22 public static void main(String[] args) 23 { 24 Test t1 = new Test("one"); 25 Test t2 = new Test("two"); 26 t1.start(); 27 t2.start(); 28 //t1.run(); 29 //t2.run(); 30 31 for (int x=0;x<60 ;x++ ) 32 { 33 System.out.println("Hello world---"+x); 34 } 35 } 36 } 37 //总结:多线程提高了程序运行效率,避免了程序运行等待。
1 //java基础教程视频第11天-05-多线程(线程运行状态 ) 2 /* 3 线程运行状态有分四种的,有分五种的,还有分六种的,这里我们以四种为例:(此处有一个图例) 4 假设创建了多个线程,运行了start()方法后启动线程,这之后线程就有几种运行方式: 5 第一种就是既有运行资格,又有执行权的运行状态, 6 第二种就是只有运行资格,但没有执行权的阻塞等待状态, 7 第三种是既没有运行资格,又没有执行权的冻结状态(其中冻结状态又分睡眠状态sleep(time)和等待状态wait(),notify()), 8 第四种就是消亡状态,消亡状态既可以在运行状态下消亡,也可以再冻结状态下消亡,消亡状态有两种方式stop()和run结束?????? 9 10 */ 11 12 class ThreadDemo3 13 { 14 public static void main(String[] args) 15 { 16 System.out.println("Hello World!"); 17 } 18 }
1 //java基础视频教程11天-06-多线程(获取线程对象以及名称) 2 /* 3 获取线程名称和设置线程名称: 4 其实多线程有他自己的默认的名称,默认名称是Thread-编号,编号从0开始 5 Thread类中有setName()和getName()方法,自然而然就有记录name的变量,所以子类继承Thread的setName和getName方法,可以直接用父类的构造方法传值 6 7 获取当前线程的对象引用: 8 其实就是调用的Thread类的静态方法currentThread() 9 10 */ 11 class Test extends Thread 12 { 13 private String name;//这句话不要了,因为,父类中已经有了 14 Test(String name) 15 { 16 super(name); 17 } 18 19 public void run() 20 { 21 for (int x=0;x<60 ;x++ ) 22 { 23 System.out.println((Thread.currentThread()==this)+"+++++"+this.getName()+"---run---"+x); //其实这里的Thread.currentThread()就相当于this 24 } //这里Thread.currentThread()返回的是这个对象的引用,并且,currentThread()方法是静态的 25 } 26 } 27 class ThreadDemo4 28 { 29 public static void main(String[] args) 30 { 31 Test t1 = new Test("aaaaaaaaaaaaaaa"); 32 Test t2 = new Test("bbbbbbbbbbbbbbb"); 33 t1.start(); 34 t1.setName("cccccccccccc"); 35 t2.start(); 36 t2.setName("dddddddddddd"); 37 //t1.run(); 38 //t2.run(); 39 40 for (int x=0;x<60 ;x++ ) 41 { 42 System.out.println("Hello world---"+x); 43 } 44 } 45 }
1 //java基础视频教程第11天-07-多线程(售票的例子) 2 /* 3 需求:卖100张票,要求用四个窗口同时卖 4 */ 5 class Ticket extends Thread 6 { 7 private static int Ticket = 100; //如果不是静态数据,则每个线程都会执行100张票,设置为静态就可以共享同一个数据 8 public void run() //但是我们一般不定义静态,因为静态数据生命周期太长了 9 { 10 if(Ticket>0) 11 { 12 while(true) 13 { 14 if(Ticket>0) 15 { 16 System.out.println(Thread.currentThread().getName()+"_____"+(Ticket--)); 17 //System.out.println(currentThread().getName()+"_____"+Ticket); //currentThread()被子类继承了所以没有写Thread.并且它是一个静态方法 18 //Ticket--; //这种写法和上面的写法相比有问题,这种写法会执行100四次,为什么,我怀疑是加载线程的时候同时加入了没有加锁的缘故 19 } 20 } 21 } 22 } 23 } 24 class TicketDemo 25 { 26 public static void main(String[] args) 27 { 28 Ticket t = new Ticket(); 29 Ticket t1 = new Ticket(); 30 Ticket t2 = new Ticket(); 31 Ticket t3 = new Ticket(); 32 33 t.start(); 34 t1.start(); 35 t2.start(); 36 t3.start(); 37 38 //t.start(); 39 //t.start(); 40 //t.start(); 41 //t.start(); 这样是多次启用线程,其实线程已经启动了,你再启动就会出错illegalThreadStateException无效的线程状态异常 42 43 } 44 }
1 //java基础教程第11天-08-多线程(创建线程-实现Runable接口) 2 /* 3 创建线程的第二种方法,实现Runnable接口 4 创建线程的第二种方法步骤: 5 1.创建一个类并实现Runnable接口 6 2.覆盖Runnable接口的run方法 7 为什么要覆盖run方法,因为run方法里面存放的是要执行的代码。 8 3.创建Thread线程 9 4.把Runnable的子类实例传递给Thread构造函数 10 把子类对象传递给Thread的构造函数是为了建立线程和run方法中代码之间的关系,这样可以指定Thread线程去执行run方法中的代码 11 5.调用Thread类的start方法,启动线程并调用JVM执行Runnable接口子类的run方法 12 13 14 实现方式创建线程和继承方式线程有什么区别 15 16 最大的区别就是继承方式创建线程只能单继承,如果这个方法还需要继承其他的类就不可以了,所以用接口不仅可以建立线程,而且可以继承其他类 17 还有一个区别就是run方法不再同一个位置,继承方式run方法存在Thread的子类中,而实现方式的run方法存在于Runnable的子类中 18 19 */ 20 class Ticket implements Runnable 21 { 22 private int Ticket=100; 23 public void run() 24 { 25 while(true) 26 { 27 if(Ticket>0) 28 { 29 System.out.println(Thread.currentThread().getName()+"-------"+(Ticket--)); 30 } 31 } 32 /* 33 if(Ticket>0) 34 { 35 while(true) 36 { 37 System.out.println(Thread.currentThread().getName()+"-------"+(Ticket--)); 38 } 39 } 40 这种写法为什么有问题??减完之后会一直加下去 41 */ 42 } 43 } 44 class TicketDemo1 45 { 46 public static void main(String[] args) 47 { 48 Ticket t = new Ticket(); //这个不是线程 49 Thread d1 = new Thread(t); //为什么要传t,是为了给Thread构造函数Runnable传递子类对象,这样线程才能接受到要运行的代码 50 Thread d2 = new Thread(t); 51 Thread d3 = new Thread(t); 52 Thread d4 = new Thread(t); 53 d1.start(); 54 d2.start(); 55 d3.start(); 56 d4.start(); 57 } 58 }
1 //java基础教程第11天-09-多线程(多线程安全问题) 2 /* 3 安全产生原因: 4 当多个线程操作一个共享数据时,由于CPU的高速切换,可能导致多个线程停在操作共享数据的关键位置上,当CPU切换回来之后就会导致安全错误 5 6 解决方法:用同步数据,把操作共享数据的地方加上锁,使线程只能一一进出,一个线程运行完,其它线程才能进入 7 8 同步代码块 9 synchronized(对象) //这个对象不明???????? 10 { 11 需要被同步的代码 12 } 13 14 */ 15 class Ticket implements Runnable 16 { 17 private int Ticket = 100; 18 Object obj = new Object(); 19 public void run() //run方法必须是无返回值 20 {
/*
while(true)
{
if(tick>0)
{
//安全问题,当Ticket=1时,多个线程停在这个地方了,cpu去执行其它程序去了,当CPU回来执行这个几个线程就会出现-1票等错误
//————>线程1,—————>线程2,——————>线程3,———————>线程4
System.out.println(Tread.currentThread().getName()+"...sale:"+Ticket--);
}
}
*/
21 while(true) 22 { 23 synchronized(obj) //在什么地方加同步,哪些语句在操作共享数据就在这些地方加同步,记住加对象,此处if在操作共享数据Ticket,还有输出语句在操作Ticket,所以同步加载这两个程序外 24 { 25 if(Ticket>0) 26 { 27 try 28 { 29 Thread.sleep(50); //Thread的sleep方法是静态的而且拍出了中断异常,抛出了,谁调用谁就得处理它,sleep也是一个静态方法,不过它抛了异常 30 } //sleep()方法参数放毫秒,当抛出该异常时,当前线程的中断状态被清除,此处用等待是为了模拟当没有同步时,多个程序等待在这个地方,当Ticket=1时,就有导致四个线程停在这个理,当sleep时间一过,四个都活了导致出现0,-1.-2票的情况 31 catch (Exception e) //此处不能向外抛,因为run方法是实现的接口,父类中没有抛异常,子类也不能抛,不然出错,只能在内部处理?????????????????????????????异常那章没学扎实 32 { 33 } //通过延迟可以看出多线程的安全问题,当多个线程执行同一个共享数据时,由于CPU的切换会导致多个线程停在某一个位置不动了,当CPU切换回来的时候,会导致结果出错 34 System.out.println(Thread.currentThread().getName()+"---"+(Ticket--)); 35 } 36 } 37 } 38 39 } 40 } 41 class TicketDemo2 42 { 43 public static void main(String[] args) 44 { 45 Ticket t = new Ticket(); 46 Thread d1 = new Thread(t); 47 Thread d2 = new Thread(t); 48 Thread d3 = new Thread(t); 49 Thread d4 = new Thread(t); 50 d1.start(); 51 d2.start(); 52 d3.start(); 53 d4.start(); 54 } 55 }
1 //java基础教程11天-10-多线程(多线程同步代码块) 2 /* 3 synchronized(对象) 4 { 5 需要被同步的代码 6 } 7 对象相当于锁,持有锁的线程可以同步中执行 8 没有持有锁的线程即使获取cup的执行权,也进不去,因为没有获取锁 9 10 火车上的卫生间--经典范例 11 12 同步前提 13 1.必须是两个线程火车两个线程以上 14 2.必须多个线程持有同一个锁 15 16 必须保证同步中只能有一个线程在运行 17 18 好处:解决了多线程的安全问题 19 弊端:多个线程需要判断锁,这样消耗了资源 20 21 */ 22 class Ticket implements Runnable 23 { 24 private int Ticket = 100; 25 Object obj = new Object(); 26 public void run() //run方法必须是无返回值 27 { 28 while(true) 29 { 30 synchronized(obj) //锁 31 { 32 if(Ticket>0) 33 { 34 try 35 { 36 Thread.sleep(50); //Thread的sleep方法是静态的而且拍出了中断异常,抛出了,谁调用谁就得处理它 37 } //sleep()方法参数放毫秒,当抛出该异常时,当前线程的中断状态被清除 38 catch (Exception e) //此处不能向外抛,因为run方法是实现的接口,父类中没有抛异常,子类也不能抛,不然出错,只能在内部处理 39 {} //通过延迟可以看出多线程的安全问题,当多个线程执行同一个共享数据时,由于CPU的切换会导致多个线程停在某一个位置不动了,当CPU切换回来的时候,会导致结果出错 40 System.out.println(Thread.currentThread().getName()+"---"+(Ticket--)); 41 } 42 } 43 } 44 45 } 46 } 47 class TicketDemo3 48 { 49 public static void main(String[] args) 50 { 51 Ticket t = new Ticket(); 52 Thread d1 = new Thread(t); 53 Thread d2 = new Thread(t); 54 Thread d3 = new Thread(t); 55 Thread d4 = new Thread(t); 56 d1.start(); 57 d2.start(); 58 d3.start(); 59 d4.start(); 60 } 61 }
1 //java基础教程第11天-11-多线程(多线程-同步函数) 2 /* 3 需求:银行有一个金库,两个储户来存钱,每个人存300元 4 目的:该程序是否有安全问题,如果有,如何解决? 5 6 问题的分析: 7 1.找出线程要运行的代码(run方法和add方法) 8 2.找出线程共享的数据(共享数据有b和sum) 9 3.找出那些代码在操作共享数据(b.add()和sum=sum+n以及System.out.println("sum"+sum);这里sum在操作最多,所以问题出现在这) 10 11 同步代码块和方法都是封装代码块的,所以可以把synchronized作为一个修饰符修饰方法,这个方法也就具备了同步功能 12 13 */ 14 15 class Bank 16 { 17 private int sum; 18 Object obj = new Object(); 19 public synchronized void add(int n) //这里可以抛出异常,但是Cus在调用add那里就不能抛了,那里是实现的接口 20 { 21 //synchronized(obj) //同步代码块和方法都是封装代码块的,所以可以把synchronized作为一个修饰符修饰方法,这个方法也就具备了同步功能 22 //{ 23 sum=sum+n; //这种写法可以。 24 try 25 { 26 Thread.sleep(20); //sleep()静态方法抛了异常,这里调用它就必须处理它,这里用sleep方法也是模拟多个程序运行时停在这个地方 27 } 28 catch (Exception e) 29 { 30 } 31 System.out.println("sum"+sum); 32 //} 当不加同步时,第一个线程进来存了100,此时CPU去执行其它程序去了,并没有输出这存进来的100,这个时候第二个线程进来也存了100,这时就是200了,存完之后线程一也醒了打印出的却是200,线程二也是打印的200,所以出现了错误 33 } 34 35 } 36 class Cus implements Runnable 37 { 38 Bank b = new Bank(); 39 public void run() 40 { 41 for (int x=0;x<3 ;x++ ) 42 { 43 b.add(100); 44 } 45 } 46 } 47 class BankDemo 48 { 49 public static void main(String[] args) 50 { 51 Cus c = new Cus(); 52 Thread d1 = new Thread(c); 53 Thread d2 = new Thread(c); 54 d1.start(); 55 d2.start(); 56 } 57 }
1 //java基础教程第11天-12-多线程(多线程-同步函数的锁是this) 2 /* 3 同步函数用的是this这个锁,既是本类对象 4 5 用的以下方法来验证 6 两个线程一个线程运行同步代码块,一个线程运行同步函数中,都执行买票动作 7 */ 8 class Ticket implements Runnable 9 { 10 private int Ticket=1000; 11 boolean flag = true; 12 //Object obj = new Object(); 13 public void run() 14 { if(flag) 15 { 16 while(true) 17 { 18 //synchronized(obj) //可以验证同步的连个条件,一是多个线程,二是要是同一个锁,当不是同一个锁时,会出错 19 synchronized(this) //在操作共享数据的地方加 20 { 21 if(Ticket>0) 22 { 23 try{Thread.sleep(20);}catch (Exception e){} 24 System.out.println(Thread.currentThread().getName()+"---"+(Ticket--)); 25 } 26 } 27 } 28 } 29 else 30 { 31 while(true) 32 { 33 show(); 34 } 35 } 36 } 37 public synchronized void show() //用的this锁 38 { 39 if(Ticket>0) 40 { 41 try{Thread.sleep(20);}catch (Exception e){} 42 System.out.println(Thread.currentThread().getName()+"+++"+(Ticket--)); 43 } 44 } 45 } 46 class ThisLockDemo 47 { 48 public static void main(String[] args) 49 { 50 Ticket t = new Ticket(); 51 Thread t1 = new Thread(t); 52 Thread t2 = new Thread(t); 53 t1.start(); 54 try{Thread.sleep(5);}catch (Exception e){} //首先明白这里一共有3个线程,主线程运行,当t1.start()启动后处于阻塞状态,有运行资格,但没有执行权,因为此时执行权在主线程,当主线程快速执行完之后,t1和t2去执行发现flag编程了false,所以都去执行show方法了。 55 t.flag = false; //加延迟时间是为了阻止主线程快速运行完毕。 56 t2.start(); 57 58 } 59 }
1 //java基础教程第11天-13-多线程(多线程-静态同步函数的锁是class对象) 2 /* 3 通过静态同步函数和同步代码块的对比运行出先安全问题(出现0号票),可以得知,静态同步函数和同步代码块的锁不是同一个锁 4 5 静态函数的锁是所在类的字节码文件对象(该对象的类型是Class),即 类名.class 6 */ 7 class Ticket implements Runnable 8 { 9 private static int Ticket=1000; 10 boolean flag = true; 11 //Object obj = new Object(); 12 public void run() 13 { if(flag) 14 { 15 while(true) 16 { 17 //synchronized(obj) //可以验证同步的连个条件,一是多个线程,二是要是同一个锁,当不是同一个锁时,会出错 18 synchronized(Ticket.class) //证明了静态同步函数的锁是所在类的字节码文件对象即 类名.class 19 { 20 if(Ticket>0) 21 { 22 try{Thread.sleep(20);}catch (Exception e){} 23 System.out.println(Thread.currentThread().getName()+"---"+(Ticket--)); 24 } 25 } 26 } 27 } 28 else 29 { 30 while(true) 31 { 32 show(); 33 } 34 } 35 } 36 public static synchronized void show() //当我把方法设置为静态之后,发现出现了安全问题(出现了0号票),由此可以证明当同步函数设置为静态时,锁不再是this了 37 { 38 if(Ticket>0) 39 { 40 try{Thread.sleep(20);}catch (Exception e){} 41 System.out.println(Thread.currentThread().getName()+"+++"+(Ticket--)); 42 } 43 } 44 } 45 class StaticMethodDemo 46 { 47 public static void main(String[] args) 48 { 49 Ticket t = new Ticket(); 50 Thread t1 = new Thread(t); 51 Thread t2 = new Thread(t); 52 t1.start(); 53 try{Thread.sleep(5);}catch (Exception e){} 54 t.flag = false; 55 t2.start(); 56 57 } 58 }
1 //java基础教程第11天-14-多线程(多线程-单例设计模式-懒汉式) 2 /* 3 饿汉式 4 class Single 5 { 6 private Single(){} 7 private static final Single s = new Single(); 8 public static Single getInstance() 9 { 10 return s; 11 } 12 } 13 */ 14 //懒汉式 //懒汉式用双重判断的形式来解决效率问题,通过三个线程(a,b,c)来演说双重判断的好处,懒汉式的特点在于延迟加载 15 class Single //你虽然解决了判断锁的问题,但是以后每个线程每次运行时都会去判断s=null,而且懒汉式的程序比饿汉式多了很多,所以用单例时推荐用饿汉式 16 { 17 private Singel(){} 18 private static Singel s = null; 19 public static /*synchronized*/ Single getInstance() //当线程多了之后,如果在函数上加同步的话,效率会变得很低 20 { 21 //--c 22 if(s=null) //在外面加这个就可以提高效率,避免其它线程去验证锁 23 { //--b 24 synchronized(Single.class) //静态同步锁是本类字节码文件对象,但是在这里加上同步跟上面一样,多个进程时,效率也会变低 25 { 26 if(s=null) 27 { 28 //--a 29 /* 30 --A 31 --B //当不加同步锁时,多个线程有可能阻塞在这个地方,当这两个线程运行时,就会产生两个对象了,就出现安全问题了 32 */ 33 s=new Single(); 34 //return s; ?????我把它放这个地方有没得影响 35 } 36 } 37 } 38 return s; 39 } 40 } 41 42 class SingleDemo 43 { 44 public static void main(String[] args) 45 { 46 Single s = Single.getInstance(); //返回来的是一个类类型变量 47 } 48 }
1 //java基础视屏第11天-15-多线程(多线程-死锁) 2 /* 3 所谓死锁就是在一个锁中嵌套另外一个锁,两个线程持有各自的锁,但都需要到对方的锁里面去运行 4 5 //此章节重点:有待问题解决: 6 问题1.下面两种程序,第一种(就是被注释的部分)到底是不是死锁 7 问题2.关于两个sleep设置时间的问题,当我控制函数锁中的sleep时,时间越长,出现卡住的时间为什么越久 8 */ 9 /* 10 以下是死锁吗???? 11 class Ticket implements Runnable 12 { 13 private int Ticket = 30000; 14 boolean flag = true; 15 Object obj = new Object(); 16 public void run() 17 { 18 if(flag) 19 { 20 while(true) 21 { 22 synchronized(obj) //一定要注意同步锁添加在那个地方加 23 { 24 show(); 25 } 26 } 27 28 } 29 else 30 { 31 show(); 32 } 33 } 34 public synchronized void show() 35 { 36 while(true){ 37 synchronized(obj) //一定要注意同步锁添加在那个地方加 38 { 39 if(Ticket>0) 40 { 41 //try{Thread.sleep(10);}catch (Exception e){} 42 System.out.println(Thread.currentThread().getName()+"----"+(Ticket--)); 43 } 44 } 45 } 46 } 47 } 48 这部分有问题????????????????? 49 */ 50 class Ticket implements Runnable 51 { 52 private int Ticket = 1000; 53 boolean flag = true; 54 Object obj = new Object(); 55 public void run() 56 { 57 if(flag) 58 { 59 while(true) 60 { 61 synchronized(obj) //一定要注意同步锁添加在那个地方加 62 { 63 show(); 64 } 65 } 66 67 } 68 else 69 { 70 while(true) 71 show(); 72 } 73 } 74 public synchronized void show() 75 { 76 synchronized(obj) //一定要注意同步锁添加在那个地方加 77 { 78 if(Ticket>0) 79 { 80 //try{Thread.sleep(10);}catch (Exception e){} 81 System.out.println(Thread.currentThread().getName()+"----"+(Ticket--)); 82 } 83 } 84 } 85 } 86 class DeadLockDemo 87 { 88 public static void main(String[] args) 89 { 90 Ticket t = new Ticket(); 91 Thread d1 = new Thread(t); 92 Thread d2 = new Thread(t); 93 d1.start(); 94 try{Thread.sleep(10);}catch (Exception e){} 95 t.flag = false; 96 d2.start(); 97 } 98 }
1 //java基础教程11天-15下-多线程(多线程-死锁) 2 class Test implements Runnable 3 { 4 private boolean flag; 5 Test(boolean flag) 6 { 7 this.flag = flag; 8 } 9 public void run() 10 { 11 if(flag) 12 { 13 synchronized(MyLock.lock1) 14 { 15 System.out.println("if lock1"); 16 synchronized(MyLock.lock2) 17 { 18 System.out.println("if lock2"); 19 } 20 } 21 } 22 else 23 { 24 synchronized(MyLock.lock2) 25 { 26 System.out.println("else lock2"); 27 synchronized(MyLock.lock1) 28 { 29 System.out.println("else lock1"); 30 } 31 } 32 } 33 } 34 } 35 36 class MyLock 37 { 38 static Object lock1 = new Object(); 39 static Object lock2 = new Object(); 40 } 41 class DeadLockTest 42 { 43 public static void main(String[] args) 44 { 45 Thread t1 = new Thread(new Test(true)); 46 Thread t2 = new Thread(new Test(false)); 47 t1.start(); 48 t2.start(); 49 } 50 }
1 //java基础教程视屏第12天-01-多线程(线程间通信-实例代码) 2 class Res 3 { 4 String name; 5 String sex; 6 } 7 class Input implements Runnable 8 { 9 private Res r; 10 Input(Res r) //两个线程操作同一个对象,通过传值的方式实现共用一个对象 11 { 12 this.r = r; 13 } 14 public void run() 15 { 16 int x = 0; //x一定是放在外面不要放在 17 //boolean b = true; 18 while(true) 19 { 20 if(/*b*/x==0) //if里面是一个布尔值,只有==时才能判断,而不是一个= 21 { 22 r.name = "Lucy"; 23 r.sex = "girl"; 24 //b = flase; 25 } 26 else 27 { 28 r.name = "风车车"; 29 r.sex = "男男男男男男男男男男男男"; 30 //b = true; 31 } 32 x = (x+1)%2; //在if条件的最下面改变x的值,可以改变if运行的路径,当然还有另外一种方法就是b 33 34 } 35 36 } 37 } 38 class Output implements Runnable 39 { 40 private Res r; 41 Output(Res r) 42 { 43 this.r = r; 44 } 45 public void run() 46 { 47 while(true) 48 { 49 System.out.println(r.name+"-----"+r.sex); 50 } 51 } 52 } 53 class InputOutputDemo 54 { 55 public static void main(String[] args) 56 { 57 Res r = new Res(); 58 Input in = new Input(r); 59 Output out = new Output(r); 60 Thread t1 = new Thread(in); 61 Thread t2 = new Thread(out); 62 t1.start(); 63 t2.start(); 64 } 65 }
1 //java基础教程视屏第12天-02-多线程(线程间通信-解决安全问题) 2 /* 3 此程序运行之后出现问题,导致输出时数据不匹配,Lucy的性别成为了男,风车车性别变成了girl, 4 问题出在那个地方呢?由于是两个线程共同操作一个对象数据,线程1是赋值,线程2是取值,当线程1赋值只赋了name为Lucy时,而sex没有赋值,CPU就去执行线程2了,线程2就只有把name为Lucy,sex为男的打印出来了 5 6 多个线程操作同一个数据出现了安全问题,首先想到的就是同步,同步的条件有连个,第一两个以上线程,第二操作同一个锁,这里第一个条件满足了,第二个条件不满 7 对于同步要加在什么地方,加在操作共同数据的地方,操作共同数据的地方有两个个地方。一个是输出数据的地方,一个是输入数据的地方,所以要将操作共享数据的地方用同一个锁同步,这里同一个锁可以是四个类的字符编码类文件也可以是共享的那个对象r 8 9 这个程序说明一个问题,同步的前提条件很关键,当多个线程操作同一个数据的时候,要保证同步,不然会出安全问题 10 11 */ 12 class Res 13 { 14 String name; 15 String sex; 16 } 17 class Input implements Runnable 18 { 19 private Res r; 20 Input(Res r) //两个线程操作同一个对象,通过传值的方式实现共用一个对象 21 { 22 this.r = r; 23 } 24 public void run() 25 { 26 int x = 0; //x一定是放在外面不要放在循环内部 27 //boolean b = true; 28 while(true) 29 { 30 synchronized(r) //同步锁可以放四个类的编码集对象,也可以放共享对象r 31 { 32 if(/*b*/x==0) //if里面是一个布尔值,只有==时才能判断,而不是一个= 33 { 34 r.name = "Lucy"; 35 r.sex = "girl"; 36 //b = flase; 37 } 38 else 39 { 40 r.name = "风车车"; 41 r.sex = "男男男男男男男男男男男男"; 42 //b = true; 43 } 44 45 x = (x+1)%2; //在if条件的最下面改变x的值,可以改变if运行的路径,当然还有另外一种方法就是b 46 } 47 } 48 49 } 50 } 51 class Output implements Runnable 52 { 53 private Res r; 54 Output(Res r) 55 { 56 this.r = r; 57 } 58 public void run() 59 { 60 while(true) 61 { 62 synchronized(r) 63 { 64 System.out.println(r.name+"-----"+r.sex); 65 } 66 } 67 } 68 } 69 class InputOutputDemo1 70 { 71 public static void main(String[] args) 72 { 73 Res r = new Res(); 74 Input in = new Input(r); 75 Output out = new Output(r); 76 Thread t1 = new Thread(in); 77 Thread t2 = new Thread(out); 78 t1.start(); 79 t2.start(); 80 } 81 }
1 //java基础教程视屏第12天-03-多线程(线程间通信-等待唤醒机制) 2 /* 3 通过加上同步后,通过运行发现,输出的数据都有重复一大片的,比如出现了风车车----男,连续重复出现了几次,才出现Lucy---girl 4 这是为什么呢?通过分析,发现input线程和output线程是两个独立的线程,都在抢执行资格,当input线程抢到执行权之后,就不断的向共享数据Res赋值, 5 而当output线程抢到执行权之后也不断的输出Res中的name和sex,此时的name和sex却是没有改变的,因为此时input线程没有执行权,就没有向你们赋值,所以导致了连续不断的出现几次重复的输出 6 7 如何解决这个问题呢?我们可以再共享数据中加一个标志flag,当flag为false时,表示可以赋值 8 此时input线程先把output线程处于等待然后再赋值,当input线程赋完值之后,标志flag变为true,表示有值了,并且唤醒output线程 9 ,当output线程检测到标志flag为true时就将input线程等待,当output线程输出值之后把标志flag变为false,并且叫醒input线程 10 11 notify和wait方法都是Object中的方法,都是继承过来的,wait方法抛出了异常,谁调用wait方法就只能try不能抛 12 并且notify和notifyAll方法相当于wait(0), 13 14 记住了:wait,notify,notifyAll这些方法全部用于同步里面,因为它们都持有监视器(锁) 15 //r.wait()是持有r这个锁的线程,同步会出现嵌套,加上r锁可以区别开来 16 r.notify(); //唤醒持有r这个锁的等待线程,加上r锁是为了避免同步嵌套 17 18 为什么wait方法,notify,notifyAll方法是操作线程Thread的却是定义在Object类当中,因为wait,notify,notifyAll方法都是任意对象都可以调用的方法 19 所以定义在上帝Object里面 20 */ 21 class Res 22 { 23 String name; 24 String sex; 25 boolean flag = false; 26 } 27 class Input implements Runnable 28 { 29 private Res r; 30 Input(Res r) //两个线程操作同一个对象,通过传值的方式实现共用一个对象 31 { 32 this.r = r; 33 } 34 public void run() 35 { 36 int x = 0; //x一定是放在外面不要放在循环内部 37 //boolean b = true; 38 while(true) 39 { 40 synchronized(r) //同步锁可以放四个类的编码集对象,也可以放共享对象r 41 { 42 if(r.flag) 43 try{r.wait();}catch (Exception e){} //r.wait()是持有r这个锁的线程,同步会出现嵌套,加上r锁可以区别开来 44 if(/*b*/x==0) //if里面是一个布尔值,只有==时才能判断,而不是一个= 45 { 46 r.name = "Lucy"; 47 r.sex = "girl"; 48 //b = flase; 49 } 50 else 51 { 52 r.name = "风车车"; 53 r.sex = "男"; 54 //b = true; 55 } 56 r.flag = true; //你要注意为什么这个flag要在内部赋值而不放在锁的外面,其实一开始你就应该想到那个图,赋值这块就是input线程和共享数据,flag就是共享数据里面的 57 r.notify(); //唤醒持有r这个锁的线程,加上r锁是为了避免同步嵌套//唤醒是唤醒线程池中的线程,如果有多个线程在线程池中,那就唤醒第一个被等待的线程,//还要注意一点wait,notify放在同步当中 58 //想唤醒全部用notifyAll();唤醒线程池中的全部线程 59 x = (x+1)%2; //在if条件的最下面改变x的值,可以改变if运行的路径,当然还有另外一种方法就是b 60 } 61 } 62 63 } 64 } 65 class Output implements Runnable 66 { 67 private Res r; 68 Output(Res r) 69 { 70 this.r = r; 71 } 72 public void run() 73 { 74 while(true) 75 { 76 synchronized(r) 77 { 78 if(!r.flag) 79 try{r.wait();}catch (Exception e){} 80 System.out.println(r.name+"-----"+r.sex); 81 r.notify(); 82 r.flag = false; 83 84 } 85 } 86 } 87 } 88 class InputOutputDemo2 89 { 90 public static void main(String[] args) 91 { 92 Res r = new Res(); 93 Input in = new Input(r); 94 Output out = new Output(r); 95 Thread t1 = new Thread(in); 96 Thread t2 = new Thread(out); 97 t1.start(); 98 t2.start(); 99 } 100 } 101 /* 102 wait:notify:notifyAll都是控制持有监视器(锁)的线程操作,而只有同步中才有锁的概念,所以,这些方法都用在同步中 103 104 为什么这些操作线程的方法都定义在Object中呢? 105 因为这些方法在操作同步中的线程时,都必须标明他们操作线程持有的锁, 106 也就是说只有同一个锁的等待线程才可以被同一个锁上的notify唤醒 107 也就是说等待和唤醒必须是同一把锁 108 而锁可以是任意对象,所以可以别任意对象调用的方法定义在Object类中 109 110 */
1 //java基础教程第12天-04-多线程(线程间通信-代码优化) 2 /*优化代码*/ 3 4 class Res 5 { 6 private String name; 7 private String sex; 8 boolean flag = false; 9 public synchronized void setName(String name,String sex) 10 { 11 if(flag) 12 try{this.wait();}catch (Exception e){} 13 this.name = name; 14 this.sex = sex; 15 flag = true; 16 this.notify(); 17 } 18 public synchronized void getName() 19 { 20 if(!flag) 21 try{this.wait();}catch (Exception e){} 22 System.out.println(name+"-----"+sex); 23 flag = false; 24 this.notify(); 25 } 26 27 } 28 class Input implements Runnable 29 { 30 private Res r; 31 Input(Res r) 32 { 33 this.r = r; 34 } 35 public void run() 36 { 37 int x = 0; 38 while(true) 39 { 40 if(x==0) 41 r.setName("lucy","woman"); 42 else 43 r.setName("风车车","男"); 44 x = (x+1)%2; 45 46 } 47 48 } 49 } 50 class Output implements Runnable 51 { 52 private Res r; 53 Output(Res r) 54 { 55 this.r = r; 56 } 57 public void run() 58 { 59 while(true) 60 { 61 r.getName(); 62 } 63 } 64 } 65 class InputOutputDemo3 66 { 67 public static void main(String[] args) 68 { 69 Res r = new Res(); 70 new Thread(new Input(r)).start(); //简化 71 new Thread(new Output(r)).start(); 72 /* 73 Input in = new Input(r); 74 Output out = new Output(r); 75 Thread t1 = new Thread(in); 76 Thread t2 = new Thread(out); 77 t1.start(); 78 t2.start(); 79 */ 80 } 81 }
1 //java基础视频教程12天-05-多线程(线程间通信-生产者消费者) 2 3 /* 4 //以下是生产者一个,消费者一个的情况 5 class ProducerConsumerDemo 6 { 7 public static void main(String[] args) 8 { 9 Resource r = new Resource(); 10 Input in = new Input(r); 11 Output out = new Output(r); 12 Thread t1 = new Thread(in); 13 Thread t2 = new Thread(out); 14 t1.start(); 15 t2.start(); 16 17 } 18 } 19 20 class Resource 21 { 22 private String name; 23 boolean flag = false; 24 private int count = 1; 25 public synchronized void set(String name) 26 { 27 if(flag) 28 try{this.wait();}catch (Exception e){} 29 this.name = name+"---"+count++; 30 System.out.println("生产了:"+Thread.currentThread().getName()+"---"+this.name); 31 flag = true; 32 this.notify(); 33 } 34 public synchronized void get() 35 { 36 if(!flag) 37 try{this.wait();}catch (Exception e){} 38 System.out.println("消费了:"+Thread.currentThread().getName()+"----"+this.name); 39 flag = false; 40 this.notify(); 41 } 42 } 43 class Input implements Runnable 44 { 45 private Resource r; 46 Input(Resource r) 47 { 48 this.r = r; 49 } 50 public void run() 51 { 52 while(true) 53 { 54 r.set("鸡蛋"); 55 } 56 } 57 } 58 class Output implements Runnable 59 { 60 private Resource r; 61 Output(Resource r) 62 { 63 this.r = r; 64 } 65 public void run() 66 { 67 while(true) 68 { 69 r.get(); 70 } 71 } 72 } 73 */ 74 75 //以下代码要求生产者多个,消费者多个,这个时候用到while和notifyAll,而非用if和notify 76 class ProducerConsumerDemo 77 { 78 public static void main(String[] args) 79 { 80 81 82 Resource r = new Resource(); 83 new Thread(new Input(r)).start(); 84 new Thread(new Input(r)).start(); 85 new Thread(new Output(r)).start(); 86 new Thread(new Output(r)).start(); 87 /* 88 Resource r = new Resource(); 89 Input in = new Input(r); 90 Output out = new Output(r); 91 Thread t1 = new Thread(in); 92 Thread t2 = new Thread(in); 93 Thread t3 = new Thread(out); 94 Thread t4 = new Thread(out); 95 t1.start(); 96 t2.start(); 97 t3.start(); 98 t4.start(); 99 */ 100 } 101 } 102 103 class Resource 104 { 105 private String name; 106 boolean flag = false; 107 private int count = 1; 108 public synchronized void set(String name) 109 { 110 /* 111 分析:当有两个生产者和两个消费时,生产者以A,B线程,消费者C,D线程,当条件是if(flag)和notify()而非while(flag)和notify()时,为什么会出现生产多个却消费一个,或者是生产一个消费两次呢?下面我们就来分析一下代码 112 当程序一开始,flag为false,假如生产者A线程进入生产并同步锁定,生产完后flag变为true,并唤醒线程池中最先被sleep的线程(此时线程中并没有sleep的线程),此时A线程任然持有执行权,但此时flag变为了true,A线程进入sleep状态 113 之后B,C,D线程抢执行权,假如B抢到了也会进入sleep状态,然后就是C,D消费线程抢执行权,假如C抢到了,并执行了消费,然后把flag变为了false,并唤醒notify线程池中最先被sleep的线程A,此时C线程仍然持有执行权,但是flag变为了false 114 ,C线程进入sleep状态,然后或者的线程只有A,D线程,假如D线程抢到执行权也是进入sleep状态,此时只有A没有进入sleep状态,A生产完之后,flag变为了true,并唤醒线程池中最先被sleep的线程,这个线程是生产者B,而非消费者C,D。这个生产者B 115 是在sleep状态下,并没有回去判断if(flag),所以它直接就去生产了,这就导致了生产了两次,而消费了一次,同理,生产一次,消费两次。 116 117 解决方法,让线程B回去读flag标志,用while(flag)而不用if(flag),并且唤醒线程池中所有的线程用notifyAll(),此时也就唤醒了消费者的线程; 118 119 120 总结,当两个线程时,一个生产,一个消费用if和notify,当多个生产,多个消费用while和notifyAll 121 */ 122 while(flag) 123 try{this.wait();}catch (Exception e){} 124 this.name = name+"---"+count++; 125 System.out.println("生产了:"+Thread.currentThread().getName()+"---"+this.name); 126 flag = true; 127 this.notifyAll(); 128 } 129 public synchronized void get() 130 { 131 while(!flag) 132 try{this.wait();}catch (Exception e){} 133 System.out.println("消费了:"+Thread.currentThread().getName()+"----"+this.name); 134 flag = false; 135 this.notifyAll(); 136 } 137 } 138 class Input implements Runnable 139 { 140 private Resource r; 141 Input(Resource r) 142 { 143 this.r = r; 144 } 145 public void run() 146 { 147 while(true) 148 { 149 r.set("鸡蛋"); 150 } 151 } 152 } 153 class Output implements Runnable 154 { 155 private Resource r; 156 Output(Resource r) 157 { 158 this.r = r; 159 } 160 public void run() 161 { 162 while(true) 163 { 164 r.get(); 165 } 166 } 167 }
1 //java基础视频教程12天-06-多线程(线程间通信-生产者消费者JDK5.0升级) 2 3 /* 4 JDK1.5中提供了多线程升级解决方案 5 将同步synchronized替换成现实lock操作 6 将Object中的wait,notify,notifyAll,替换为Condition对象 7 该对象可以通过Lock锁进行获取 8 该实例中,实现了本方只唤醒对方的线程 9 10 生产者与消费者有什么替代方案 11 1.5JDK提供了显示的锁机制,以及显示锁对象上的等待唤醒操作机制,它把等待唤醒进行了封装,封装完一个锁对应多个Condition 12 */ 13 import java.util.concurrent.locks.*;//最重要的一点,要导入JDK 1.5新特性的包 14 class ProducerConsumerDemo2 15 { 16 public static void main(String[] args) 17 { 18 19 20 Resource r = new Resource(); 21 new Thread(new Input(r)).start(); 22 new Thread(new Input(r)).start(); 23 new Thread(new Output(r)).start(); 24 new Thread(new Output(r)).start(); 25 /* 26 Resource r = new Resource(); 27 Input in = new Input(r); 28 Output out = new Output(r); 29 Thread t1 = new Thread(in); 30 Thread t2 = new Thread(in); 31 Thread t3 = new Thread(out); 32 Thread t4 = new Thread(out); 33 t1.start(); 34 t2.start(); 35 t3.start(); 36 t4.start(); 37 */ 38 } 39 } 40 /* 41 class Resource 42 { 43 private String name; 44 boolean flag = false; 45 private int count = 1; 46 private Lock lock =new ReentrantLock(); //首先注明下,Lock是一个接口,而ReentrantLock只是实现它的一个子类。Lock还有其它的子类,这样就建立了锁,Lock类中有lock方法和unlock方法,ReentrantLock继承多来了 47 private Condition condition= lock.newCondition(); //这里要说明一下,Lock接口里面有newCondition(),这个方法是创建一个绑定到该锁的Condition对象,为什么要这样做呢?因为Condition接口中有await和signal,signalAll方法,这些方法都是存在于同步中,而同步必须用到锁 48 public void set(String name) throws InterruptedException 49 { 50 lock.lock(); 51 try 52 { 53 while(flag) 54 condition.await(); //Conditon的await方法抛了异常,调用它就必须处理,这里采用抛异常, 55 this.name = name+"---"+count++; //为什么要把无关的代码放进try里面??????????????????????????????待解决??????????????????? 56 System.out.println("生产了:"+Thread.currentThread().getName()+"---"+this.name); 57 flag = true; 58 condition.signalAll(); //此处signal()相当于notify(),signalAll相当于notifyAll,此处如果写signal()就使所有线程进入等待,程序将停止,为了防止所有线程进入等待这里用的signalAll,唤醒全部等待的线程 59 } 60 finally 61 { 62 lock.unlock(); 63 } 64 65 66 67 } 68 public void get() throws InterruptedException 69 { 70 lock.lock(); 71 try 72 { 73 while(!flag) 74 condition.await(); 75 System.out.println("消费了:"+Thread.currentThread().getName()+"----"+this.name); //问题?关于try的区域到底该放些什么东西 76 flag = false; 77 condition.signalAll(); 78 } 79 finally 80 { 81 lock.unlock(); 82 } 83 } 84 } 85 以上代码就是上个版本的翻版 86 */ 87 class Resource 88 { 89 private String name; 90 boolean flag = false; 91 private int count = 1; 92 private Lock lock =new ReentrantLock(); 93 private Condition condition_set = lock.newCondition(); 94 private Condition condition_get = lock.newCondition(); //JDK api 1.5最厉害之处吗??提供了一个锁可以绑定多个Condition对象。 95 public void set(String name) throws InterruptedException 96 { 97 lock.lock(); 98 try 99 { 100 while(flag) 101 condition_set.await(); 102 this.name = name+"---"+count++; //为什么要把无关的代码放进try里面??????????????????????????????待解决??????????????????? 103 System.out.println("生产了:"+Thread.currentThread().getName()+"---"+this.name); 104 flag = true; 105 condition_get.signalAll(); //此处signal()相当于notify(),signalAll相当于notifyAll,此处如果写signal()就使所有线程进入等待,程序将停止,为了防止所有线程进入等待这里用的signalAll,唤醒全部等待的线程 106 } //为了只唤醒对方的线程,可以设定特定的Condition对象 107 finally 108 { 109 lock.unlock(); 110 } 111 112 113 114 } 115 public void get() throws InterruptedException 116 { 117 lock.lock(); 118 try 119 { 120 while(!flag) 121 condition_get.await(); 122 System.out.println("消费了:"+Thread.currentThread().getName()+"----"+this.name); //问题?关于try的区域到底该放些什么东西 123 flag = false; 124 condition_set.signalAll(); 125 } 126 finally 127 { 128 lock.unlock(); //注意哈,一定要开锁, 129 } 130 } 131 } 132 class Input implements Runnable 133 { 134 private Resource r; 135 Input(Resource r) 136 { 137 this.r = r; 138 } 139 public void run() 140 { 141 while(true) 142 { 143 try 144 { 145 r.set("妹纸"); 146 } 147 catch (InterruptedException e) 148 { 149 } 150 } 151 } 152 } 153 class Output implements Runnable 154 { 155 private Resource r; 156 Output(Resource r) 157 { 158 this.r = r; 159 } 160 public void run() 161 { 162 while(true) 163 { 164 try 165 { 166 r.get(); 167 } 168 catch (InterruptedException e) 169 { 170 } 171 } 172 } 173 }
1 //java基础视频教程第12天-07-多线程(停止线程) 2 /* 3 要解决停止线程就控制住线程中的循环就可以,这个通过控制循环条件改变 4 多线程一般都是循环运行的,想要停止线程就是停止run方法,只要控制循环条件就可以结束run方法 5 //我搞不清楚这个三个线程运行循序的先后导致不同的结果,有问题,带解决 6 class StopThread implements Runnable 7 { 8 private boolean flag = true; 9 int y=0; 10 public void run() 11 { 12 13 while(flag) 14 { 15 System.out.println(Thread.currentThread().getName()+"---"+"run"+y); 16 y++; 17 } 18 } 19 public void ChangeFlag() 20 { 21 flag = false; 22 } 23 } 24 class StopThreadDemo 25 { 26 public static void main(String[] args) 27 { 28 int x=0; 29 StopThread st = new StopThread(); 30 Thread t1 = new Thread(st); 31 Thread t2 = new Thread(st); 32 t1.start(); 33 t2.start(); 34 35 36 while(true) 37 { 38 if(x++==60) //是==,不是=。 39 { 40 st.ChangeFlag(); 41 break; //if在控制break,当x=60时先改变flag的值,然后退出当前while循环 42 } 43 System.out.println(Thread.currentThread().getName()+"---"+x); //主线程也有名称,它的名称就是main 44 } 45 System.out.println("OVER!"+x); 46 } 47 } 48 */ 49 50 //有种情况控制不了,那就是同步时线程进入了等待,睡眠状态而没有唤醒,这个时候即使你改变了flag标志,但线程仍在等待中,读取不到改变的标志,导致程序没有停下来的 51 52 class StopThread implements Runnable 53 { 54 private boolean flag = true; 55 public synchronized void run() 56 { 57 while(flag) 58 { 59 try 60 { 61 wait(); //当线程在这儿冻结时,其它线程获取执行权就进来了 62 } 63 catch (InterruptedException d) 64 { 65 System.out.println(Thread.currentThread().getName()+"---"+"InterruptedException"); 66 flag = false; //在处理异常中把flag变为false,强制结束线程 67 } 68 System.out.println(Thread.currentThread().getName()+"---"+"run"); 69 } 70 } 71 public void ChangeFlag() 72 { 73 flag = false; 74 } 75 } 76 class StopThreadDemo 77 { 78 public static void main(String[] args) 79 { 80 int x=0; 81 StopThread st = new StopThread(); 82 Thread t1 = new Thread(st); 83 Thread t2 = new Thread(st); 84 t1.start(); 85 t2.start(); 86 87 88 while(true) 89 { 90 if(x++==60) //是==,不是=。 91 { 92 t1.interrupt(); //Thread中提供了静态interrupt方法专门用于唤醒中断中的线程,要注意中断的线程不是停止线程,也就是说interrupt只用于唤醒jion,wait和sleep,而不能用于唤醒stop 93 t2.interrupt(); //强制,唤醒中断中的线程t2 94 //st.ChangeFlag(); //这里也可以也 95 break; //if在控制break,当x=60时先改变flag的值,然后退出当前while循环 96 } 97 System.out.println(Thread.currentThread().getName()+"---"+x); //主线程也有名称,它的名称就是main 98 } 99 System.out.println("OVER!"+x); 100 } 101 }
1 //java基础视频教程第12天-08天-多线程(守护线程) 2 /* 3 注意: 4 守护线程相当于后天线程, 5 Thread线程提供了setDaemon方法设置守护线程,该方法必须在启动线程钱调用 6 并且当全都剩下守护线程了java虚拟机退出 7 */ 8 class StopThread implements Runnable 9 { 10 private boolean flag = true; 11 public synchronized void run() 12 { 13 while(flag) 14 { 15 try 16 { 17 wait(); 18 } 19 catch (InterruptedException e) 20 { 21 System.out.println(Thread.currentThread().getName()+"---"+"Exception"); 22 } 23 System.out.println(Thread.currentThread().getName()+"---"+"run"); 24 } 25 } 26 public void ChangeFlag() 27 { 28 flag = false; 29 } 30 } 31 class StopThreadDemo1 32 { 33 public static void main(String[] args) 34 { 35 int x=0; 36 StopThread st = new StopThread(); 37 Thread t1 = new Thread(st); 38 Thread t2 = new Thread(st); 39 t1.setDaemon(true); 40 t2.setDaemon(true); //成为守护线程必须在启动线程之前 41 //所谓的守护线程其实在开启和运行时跟一般线程没有区别,都会抢CPU的资源,不同点在于结束的时候,当所有的前头线程都结束后,后台线程(守护线程)会自动结束 42 t1.start(); 43 t2.start(); 44 45 46 while(true) 47 { 48 if(x++==60) 49 { 50 //t1.interrupt(); 51 //t2.interrupt(); 52 break; 53 } 54 System.out.println(Thread.currentThread().getName()+"---"+x); 55 } 56 System.out.println("OVER!"+x); 57 } 58 }
1 //java基础教程第12天-09-多线程(join方法) 2 /* 3 join作用:当A线程执行到B线程的join方法时,A就会等待B线程执行完毕后才会活过来 4 5 join用于临时加入线程运行 6 */ 7 8 class Demo implements Runnable 9 { 10 public void run() 11 { 12 for (int x=0;x<70 ;x++ ) 13 { 14 System.out.println(Thread.currentThread().getName()+"---"+x); 15 } 16 } 17 } 18 class JoinDemo 19 { 20 public static void main(String[] args) throws InterruptedException //join必须抛异常 21 { 22 Demo d = new Demo(); 23 Thread t1 = new Thread(d); 24 Thread t2 = new Thread(d); 25 t1.start(); 26 t1.join(); //join放这里,分析:当主线程运行到这里,已近启动了t1线程,然后遇到t1的join方法就会把执行权交给t1,直到t1执行完毕才主线程才会活过来 27 t2.start(); 28 //t1.join(); //join加在这里,分析:当主线程开启了t1和t2线程之后遇到t1的join方法,就会把执行权交给t1,自己就处于冻结状态,之后t1和t2就会交互抢夺CPU执行权,直到t1执行完后主线程才活过来。 29 for (int x=0;x<80 ;x++ ) 30 { 31 System.out.println("main----"+x); 32 } 33 } 34 }
1 //java基础视频教程第12天-10-多线程(优先级&yield方法) 2 /* 3 首先Thread继承了Object的toString方法,并重写了。主要包括有线程名称,优先级,线程组 4 线程组是ThreadGroup,优先级是setPriority,本来优先级分为1-10个等级,但是为了效果 5 就分为了3个等级,1,5,10,并用常量表示分别是MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY 6 */ 7 /* 8 class Demo implements Runnable 9 { 10 boolean flag = true; 11 int y; 12 public synchronized void run() 13 { 14 for(int x=0;x<70;x++) 15 { 16 System.out.println(Thread.currentThread().toString()+"-----"+(y++)); 17 Thread.yield(); //暂停当前执行的线程对象,并执行其它线程,当某个线程读到它就会释放执行权,别的线程就会执行 18 } //我测试没效果 19 } 20 } 21 class 22 { 23 public static void main(String[] args) 24 { 25 int x=0; 26 Demo d = new Demo(); 27 Thread t1 = new Thread(d); 28 Thread t2 = new Thread(d); 29 t1.start(); 30 //t1.setPriority(Thread.MAX_PRIORITY); //注意优先级设置成了静态字段,用类调用,0线程设置成优先级为10之后抢执行权多些 31 t2.start(); 32 33 34 } 35 } 36 */ 37 //如何写多线程 38 class PriorityDemo 39 { 40 public static void main(String[] args) 41 { 42 new Thread() 43 { 44 public void run() 45 { 46 for (int x=0;x<60 ;x++ ) 47 { 48 System.out.println(x); 49 } 50 } 51 }.start(); 52 53 for (int x=0;x<60 ;x++ ) 54 { 55 System.out.println(x); 56 } 57 58 Runnable r = new Runnable() 59 { 60 public void run() 61 { 62 for (int x=0;x<60 ;x++ ) 63 { 64 System.out.println(x); 65 } 66 } 67 }; 68 new Thread(r).start(); 69 } 70 }
1 //break和continue区别 2 /* 3 1.break和continue语句的作用范围,break作用范围是switch和loop,而continue范围是loop 4 2.break和continue单独存在时,下面不能跟语句,不然出错 5 3.break是退出当前循环不在执行这个循环,而continue是退出本次循环继续下一次循环 6 */ 7 class break_continue 8 { 9 public static void main(String[] args) 10 { 11 /* 12 for (int x=0;x<10 ;x++ ) 13 { 14 System.out.println("x="+x); 15 break; //break叫做退出当前循环 这个结果是x=0 16 } 17 */ 18 /* 19 for (int x=0;x<10 ;x++ ) 20 { 21 break; //当break单独存在时,它的下面不能有语句,否者执行不到,JVM会认为这是一种错误 22 System.out.println("x="+x); 23 } 24 */ 25 /* 26 for (int x=0;x<10 ;x++ ) 27 { 28 if(x%2==1) 29 { 30 break; //当然当break被if控制时,它下面还是可以出现语句的 31 } 32 System.out.println("x="+x); //结果是x=0 33 } 34 */ 35 36 W:for (int x=0;x<10 ;x++ ) 37 { 38 N:for (int y=0;y<10 ;y++ ) //给循环编号 39 { 40 System.out.println("x="+x); 41 break N; //退出N循环,执行外面循环,结果是0-9 42 //break W; //只打印x=0,然后退出W循环,程序结束 43 } 44 } 45 46 /***********************************************************************************************************/ 47 /* 48 for (int x=0;x<10 ;x++ ) 49 { 50 continue; //这个会报错,因为当continue单独存在时,下面不能有语句 51 System.out.println("x="+x); 52 } 53 */ 54 /* 55 for (int x=0;x<10 ;x++ ) 56 { 57 if(x%2==1) 58 continue; //当continue被if控制时下面可以出现语句 59 System.out.println("x="+x); //打印出偶数 60 } 61 */ 62 63 /* 64 W:for (int x=0;x<10 ;x++ ) 65 { 66 N:for (int y=0;y<10 ;y++ ) 67 { 68 System.out.println("x="+x); 69 //continue N; 加与不加都一样 70 continue W; //0-9 71 } 72 } 73 */ 74 } 75 }