Java多线程基础(二)
1.多线程数据安全
线程同步:多个线程需要访问同一资源时,需要以某种顺序来确定该资源某一时刻只能被一个线程使用。
2.同步代码块实现同步(部分代码的访问,我们希望它同步)
package com.test; public class ThreadDemo1 { public static void main(String[] args) { // TODO Auto-generated method stub //创建共享资源对象 TicketRes ticketRes=new TicketRes(); //创建线程对象 Thread w1=new Thread(ticketRes,"窗口1"); Thread w2=new Thread(ticketRes,"窗口2"); Thread w3=new Thread(ticketRes,"窗口3"); w1.start(); w2.start(); w3.start(); } } //共享资源类 class TicketRes implements Runnable{ private int ticket=100; private Object lock=new Object();//锁 @Override public void run() { // TODO Auto-generated method stub while(true) { synchronized (lock) { if(ticket>=1) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票"); ticket--; }else { break; } } } } }
View Code
3.同步方法实现同步(强调功能,方法的访问是同步的)
package com.test; public class ThreadDemo2 { public static void main(String[] args) { // TODO Auto-generated method stub //创建共享资源对象 TicketRes1 ticketRes=new TicketRes1(); //创建线程对象 Thread w1=new Thread(ticketRes,"窗口1"); Thread w2=new Thread(ticketRes,"窗口2"); Thread w3=new Thread(ticketRes,"窗口3"); w1.start(); w2.start(); w3.start(); } } //共享资源类 class TicketRes1 implements Runnable{ private static int ticket=100; private Object lock=new Object();//锁 @Override public void run() { // TODO Auto-generated method stub while(true) { if(!TicketRes1.saleTicket()) { break; } } } public synchronized static boolean saleTicket() { if(ticket>=1) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票"); ticket--; return true; }else { return false; } } }
View Code
4.锁的概念以及死锁问题
多线程在运行的时候可能会遇到这样的问题,多个线程要用到同一个资源,那可能会出现错乱,比如线程要改动资源里的数据,那么多个线程同时改就乱了套了。就像公共厕所,必须要一个一个接着上,不能两个人或者多个人同时上。那么锁这个概念就是像上厕所的门,一个人在上厕所,锁上了门,那下一个人就不能进去了。同样的,如果我们想让某一个程序或者某一个变量只能同时被一个线程运行,就得给程序上锁。所以上了锁,就能保证线程有秩序地运行。
接下来看一个死锁的Java实例(是不是停不下来了,就相当于循环语句的死循环)
package com.test; public class DeadLock { public static void main(String[] args) { // TODO Auto-generated method stub DeadLockThread he=new DeadLockThread(true,"小明");//他 DeadLockThread she=new DeadLockThread(false,"小华 ");//她 he.start(); she.start(); } } //线程 class DeadLockThread extends Thread{ boolean flag=false; public DeadLockThread() { } protected DeadLockThread(boolean flag,String name) { super(name); this.flag=flag; } public void run() { while(true) { if(flag) { synchronized (Lock.locka) {//他 System.out.println(Thread.currentThread().getName()+"抢到了locka"); } synchronized (Lock.lockb) { System.out.println(Thread.currentThread().getName()+"抢到了lockb"); System.out.println(Thread.currentThread().getName()+"可以上厕所了"); } }else { synchronized (Lock.lockb) {//她 System.out.println(Thread.currentThread().getName()+"抢到了lockb"); } synchronized (Lock.locka) { System.out.println(Thread.currentThread().getName()+"抢到了locka"); System.out.println(Thread.currentThread().getName()+"可以上厕所了"); } } } } } //创建锁对象 class Lock{ public static Object locka=new Object(); public static Object lockb=new Object(); }
View Code
5.线程终止
1.使用标志,使run()方法正常执行完毕
package com.test; import java.util.Scanner; public class Demo1 { public static void main(String[] args) { // TODO Auto-generated method stub FlagStop flagStop=new FlagStop("线程1"); flagStop.start(); Scanner input=new Scanner(System.in); System.out.println("输入任意字符结束主线程"); input.next(); flagStop.flag=false;//主线程修改其他线程的变量 System.out.println("主线程结束"); } } class FlagStop extends Thread{ //定义标志 volatile:易挥发的、不稳定的,使用volatile修饰后,获取变量不会从缓存中取,从内存中取。 volatile boolean flag=true; public FlagStop() { // TODO Auto-generated constructor stub } public FlagStop(String name) { super(name); // TODO Auto-generated constructor stub } @Override public void run() { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName()+"开始执行了"); while(flag) { } System.out.println(Thread.currentThread().getName()+"执行完毕"); } }
View Code
2.使用stop方法强制终止线程
package com.test; import java.util.Scanner; public class Demo2 { public static void main(String[] args) { // TODO Auto-generated method stub WordStop wordStop=new WordStop("线程1"); wordStop.start(); Scanner input=new Scanner(System.in); System.out.println("输入任意字符结束主线程"); input.next(); wordStop.stop(); wordStop.flag=false;//主线程修改其他线程的变量 System.out.println("主线程结束"); } } class WordStop extends Thread{ //定义标志 volatile:易挥发的、不稳定的,使用volatile修饰后,获取变量不会从缓存中取,从内存中取。 volatile boolean flag=true; public WordStop() { // TODO Auto-generated constructor stub } public WordStop(String name) { super(name); // TODO Auto-generated constructor stub } @Override public void run() { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName()+"开始执行了"); while(flag) { } System.out.println(Thread.currentThread().getName()+"执行完毕"); } }
View Code
3.使用interrupt方法中断线程
package com.test; import java.io.IOException; public class Demo3 { public static void main(String[] args) throws IOException, InterruptedException { // TODO Auto-generated method stub InterruptStop interruptStop=new InterruptStop(); interruptStop.start(); System.out.println("在10秒之内输入任意符号结束"); System.in.read(); interruptStop.interrupt();//打断正在休眠的线程 interruptStop.join(); System.out.println("主线程结束..."); } } class InterruptStop extends Thread{ @Override public void run() { try { Thread.sleep(10000);//抛出一个异常InterruptedException } catch (InterruptedException e) { // TODO Auto-generated catch block // e.printStackTrace(); System.out.println("执行了catch"); } System.out.println("子线程执行完毕"); } }
View Code
6.线程间通信
1.wait:挂起当前线程,释放共享资源锁
2.notify:在所有的wait线程当中随机选择一条唤醒
3.notifyAll:唤醒全部wait线程