package com.btp.t4.多线程; /* * 单线程:一条线可以串起来的 */ public class TestMain{ public static void main(String[] args){ method2("btp"); } private static void method2(String str) { // TODO 自动生成的方法存根 System.out.println("method2"); method1(str); } private static void method1(String str) { // TODO 自动生成的方法存根 System.out.println("method1"); System.out.println(str); } }
package com.btp.t4.多线程; /* * 创建一个子线程,完成1-100之间自然数的输出。同样地,主线程执行同样的操作 * 创建多线程的第一种方式:继承Thread类 */ public class TestThread { public static void main(String[] args){ //3.创建一个子类的对象 SubThread st=new SubThread(); //4.调用线程的start()方法:启动此线程;调用相应的run()方法 st.start();//一个线程对象只能够执行一次start(),可以再创建一个对象 //st.run();//只调用run().并没有启动此线程 SubThread st1=new SubThread(); st1.start(); for(int i=1;i<=100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } } //1.创建一个继承Thread的子类 class SubThread extends Thread{ //2.重写Thread类的run()方法。方法内实现此子线程要完成的功能 public void run(){ for(int i=1;i<=100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
package com.btp.t4.多线程; public class TestThread1 { public static void main(String[] args) { PrintNum1 p=new PrintNum1(); Thread t1=new Thread(p); Thread t2=new Thread(p); t1.start(); t2.start(); } } class PrintNum1 implements Runnable{ @Override public void run() { // TODO 自动生成的方法存根 for(int i=1;i<=100;i++) { if(i%2==0)System.out.println(Thread.currentThread().getName()+":"+i); } } }
package com.btp.t4.多线程; public class TestTwoThread { public static void main(String[] args){ // Thread t1=new Thread1(); // t1.start(); // t1=new Thread2(); // t1.start(); new Thread(){ public void run(){ for(int i=1;i<=100;i++) { if(i%2==0)System.out.println(Thread.currentThread().getName()+":"+i); } } }.start(); new Thread(){ public void run(){ for(int i=1;i<=100;i++) { if(i%2!=0)System.out.println(Thread.currentThread().getName()+":"+i); } } }.start(); } } class Thread1 extends Thread{ public void run(){ for(int i=1;i<=100;i++) { if(i%2==0)System.out.println(Thread.currentThread().getName()+":"+i); } } } class Thread2 extends Thread{ public void run(){ for(int i=1;i<=100;i++) { if(i%2!=0)System.out.println(Thread.currentThread().getName()+":"+i); } } }
package com.btp.t4.多线程; /* * 继承的方式:模拟火车站售票窗口,开启三个窗口售票,总票数为100张 * 存在线程安全问题 */ public class TestWindow { public static void main(String[] kobe) { Window w1=new Window(); Window w2=new Window(); Window w3=new Window(); w1.setName("窗口1"); w2.setName("窗口2"); w3.setName("窗口3"); w1.start(); w2.start(); w3.start(); } } class Window extends Thread{ static int ticket=100;//如果不声明为static,就是300张 //Object obj=new Object();也不能当锁,三个对象,三把锁 static Object obj=new Object();//共用一把锁 public void run(){ while(true){ synchronized(obj){//this代表当前对象,而有三个对象,所以创建了3个锁,所以不能使用this if(ticket>0){ try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--); }else{ break; } } } } }
package com.btp.t4.多线程; /* * 实现的方式:模拟火车站售票窗口,开启三个窗口售票,总票数为100张 */ /* * 创建多线程的第二种方式:通过实现的方式 * 1.创建一个实现了Runnable接口的类 * 2.实现Runnable内的Run()方法 * 3.创建一个实现类的对象 * 4.将此对象作为形参传入Thread类的构造器中,创建Thread类的对象,此对象作为一个线程 * 5.调用start()方法,执行run() * * * 对比继承的方式 VS 实现的方式 * 1.联系:Thread类本身就实现了Runnable接口 * 2.哪个方式好:实现的方式优于继承的方式 * ①实现的方式避免了java单继承的局限性 * ②如果多个线程要操作同一份资源(数据),更适合使用实现的方式 * * *此程序存在线程安全问题,打印车票时,会出现重票,错票 *1.存在的原因:由于一个线程在操作共享数据的过程中,未执行完毕的情况下,另外的线程参与进来, * 导致共享数据存在安全问题 *2.如何解决线程的安全问题? * 必须让一个线程操作共享数据完毕以后,其他线程才有机会参与共享数据的操作 *3.java如何实现线程的安全:线程的同步机制 * 方式1:同步代码块 * synchronized(同步监视器){ * //需要被同步的代码块(即为操作共享数据的代码) * } * 1.共享数据:多个线程共同操作的同一个数据(变量) * 2.同步监视器:由一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁 * 3.同步监视器可以是任何类的对象 ,要求所有线程共用一把锁 * 方式2:同步方法 * 将操作共享数据的方法声明为synchronized。即此方法为同步方法,能够保证当其中一个线程执行此方法时, * 其它线程在外等待直至此线程执行完此方法 * >同步方法的锁:this *4.线程同步的弊端:由于同一个时间只能有一个线程访问共享数据,效率变低了 */ public class TestWindow1 { public static void main(String[] args) { //要想启动一个多线程,必须调用start() //Runnable接口内并没有start()方法,只有Thread及其子类才有 //把实现Runnable接口的类的对象传入Thread构造器,通过Thread对象来调用start() Window1 w=new Window1();//只有一个Window1对象,所以只有100张票 new Thread(w).start(); new Thread(w).start(); new Thread(w).start(); } } class Window1 implements Runnable{ int ticket=100;//共享数据 Object obj=new Object();//监视器:初始是“绿灯”,每次有线程操作共享数据,就变成“红灯”,表示不允许其他线程再去操作共享数据。 //只有一个线程操作完这个共享数据,才会转为“绿灯”,再允许其他线程操作 public void run(){ while(true){ //Object obj=new Object();//也不能写在这里,写在这里就是每个线程一把锁 synchronized(obj){//这里不能写new Object();因为每次new了之后,都生成一把锁,都是“绿灯”,都允许进入。不安全。 if(ticket>0){ try { Thread.currentThread().sleep(10); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--); }else{ break; } } } } //同步方法,然后run()调用此方法就可以了 public synchronized void show() { if(ticket>0){ try { Thread.currentThread().sleep(10); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--); } } }
package com.btp.t4.多线程; /* * Thread的常用方法: * 1.start():启动线程并执行相应的run()方法 * 2.run():子线程要执行的代码放入run()方法中 * 3.Thread.currentThread():静态的,调取当前的线程 * 4.getName():获取此线程的名字 * 5.setName():设置此线程的名字 * 6.yield():调用此方法的线程释放当前CPU的执行权 * 7.join():在A线程中调用B线程的join()方法。表示:当执行到此方法,A线程停止执行,直至B线程执行完毕, * A线程再接着join()之后的代码执行 * 8.isAlive():判断当前线程是否还存活 * 9.sleep(long l):显式的让当前线程睡眠l毫秒 * 10.线程通信:wait() notify() notifyAll() * * 设置线程的优先级: * getPriority():返回线程优先级 * setPriority(ine newPriority):设置线程的优先级:概率变大了,不是百分百 * */ public class TestThreadMethod { public static void main(String[] args){ SubThread1 st1=new SubThread1(); st1.setPriority(Thread.MAX_PRIORITY); st1.start(); System.out.println(st1.getName()); st1.setName("子线程1"); Thread.currentThread().setName("主线程"); System.out.println(Thread.currentThread().getName()+"!!!!!!!!"); for(int i=1;i<=100;i++){ //if(i%10==0)Thread.currentThread().yield(); System.out.println("--------"+Thread.currentThread().getName()+":"+i); if(i==20) try { st1.join(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } //SubThread1 st2=(SubThread1) Thread.currentThread();//调用的是主线程,报错 //System.out.println(st2.getName()); System.out.println(st1.isAlive()); } } class SubThread1 extends Thread{ //2.重写Thread类的run()方法。方法内实现此子线程要完成的功能 public void run(){ try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } for(int i=1;i<=100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
package com.btp.t4.多线程; /* * 线程通信:如下的三个关键字使用的话,都得在同步代码块和同步方法中 * wait():一旦一个线程执行到wait(),就释放当前的锁 * notify()/notifyAll():唤醒wait()的一个/所有的线程 * 使用两个线程打印1-100,线程1,线程2交替打印 */ public class TestCommunication { public static void main(String[] args){ PrintNum p=new PrintNum(); new Thread(p).start(); new Thread(p).start(); } } class PrintNum implements Runnable{ int num=1; @Override public void run() { // TODO 自动生成的方法存根 while(true){ synchronized(this){ notify();//唤醒另外一个线程,但由于此时锁是本线程掌握的,所以还是本线程先执行 if(num<=100){ try { Thread.currentThread().sleep(10); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+num); num++; } try { wait();//释放本线程的锁和资源,使另外一个线程可以获得 } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } } }
package com.btp.t4.多线程; public class Practice { public static void main(String[] args) { //1.继承的方式 // Account ac=new Account(0); // Customer c1=new Customer(ac); // Customer c2=new Customer(ac); // c1.setName("账户1"); // c2.setName("账户2"); // c1.start(); // c2.start(); //2.实现的方式 Account ac1=new Account(0); Customer1 cs=new Customer1(ac1); new Thread(cs).start(); new Thread(cs).start(); } } class Account{ private int money; public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } @Override public String toString() { return "Account [money=" + money + "]"; } public Account(int money) { super(); this.money = money; } public Account() { super(); } public void addMoney(int money){ this.money+=money; } } //继承的方式 class Customer extends Thread{ Account ac=null; public Account getAc() { return ac; } public void setAc(Account ac) { this.ac = ac; } @Override public String toString() { return "Customer [ac=" + ac + "]"; } public Customer(Account ac) { super(); this.ac = ac; } public Customer() { super(); } public void addMoney(int money){ synchronized(Customer.class){ for(int i=0;i<3;i++){ try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } this.ac.addMoney(money); System.out.println(Thread.currentThread().getName()+":"+ac.getMoney()); } } } public void run(){ addMoney(1000); } } //实现的方式 class Customer1 implements Runnable{ Account ac=null; public Account getAc() { return ac; } public void setAc(Account ac) { this.ac = ac; } @Override public String toString() { return "Customer1 [ac=" + ac + "]"; } public Customer1(Account ac) { super(); this.ac = ac; } public Customer1() { super(); // TODO 自动生成的构造函数存根 } public synchronized void addMoney(int money){ for(int i=0;i<3;i++){ try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } this.ac.addMoney(money); System.out.println(Thread.currentThread().getName()+":"+ac.getMoney()); } } @Override public void run() { addMoney(1000); } }
package com.btp.t4.多线程; /* * 死锁 */ public class TestDeadLock { static StringBuffer sb1=new StringBuffer(); static StringBuffer sb2=new StringBuffer(); public static void main(String[] args){ new Thread(){ public void run(){ synchronized(sb1){ try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } sb2.append("A"); synchronized(sb2){ sb1.append("B"); System.out.println(sb1.toString()); System.out.println(sb2.toString()); } } } }.start(); new Thread(){ public void run(){ synchronized(sb2){ try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } sb2.append("C"); synchronized(sb1){ sb1.append("D"); System.out.println(sb1.toString()); System.out.println(sb2.toString()); } } } }.start(); } }
package com.btp.t4.多线程; /* * 关于懒汉式的线程安全问题:使用同步机制 * 对于一般的方法,使用同步代码块,锁可以考虑使用this * 对于静态方法而言,使用当前类本身充当锁:类名.class */ public class TestSingletonSecurity { public static void main(String[] args) { Singleton s=Singleton.returnSingleton(); Singleton s1=Singleton.returnSingleton(); System.out.println(s==s1); } } class Singleton { private Singleton(){ } private static Singleton sl=null; public static Singleton returnSingleton(){ if(sl==null){ synchronized(Singleton.class){//使用类本身作为锁,其实还是一个对象 Class cl=Singleton.class; if(sl==null)sl=new Singleton();//如果一个线程进来,发现s1==null,然后还没有创建对象,就挂起了 //这时候又有一个线程进来,发现此时s1还是null,创建对象,然后这时候 //原先那个线程挂起状态结束,运行,也创建了一个对象,这时候就有2个对象 //就是线程不安全的 } } return sl; } }
package com.btp.t4.多线程; /* * 生产者/消费者的问题 * 生产者将产品交给店员,而消费者从店员处拿走产品。店员一次只能持有固定数量的产品,如果生产者 * 试图生产更多的产品,店员会叫停一下,如果店中有空位了再通知生产者继续生产,如果店中没有产品了, * 店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。 * * 分析 * 1.是否涉及到多线程的问题?是!生产者和消费者 * 2.是否涉及到共享数据?有,即为产品数量 * 3.是否涉及到线程的通信?有。 */ public class TestProduceConsume { public static void main(String[] args) { Clerk clerk=new Clerk(0); Producter p=new Producter(clerk); Consumer c=new Consumer(clerk); Thread p1=new Thread(p); p1.setName("Producter1"); p1.start(); // // Thread p2=new Thread(p); // p2.setName("Producter2"); // p2.start(); Thread c1=new Thread(c); c1.setName("Consumer1"); c1.start(); Thread c2=new Thread(c); c2.setName("Consumer2"); c2.start(); } } class Producter implements Runnable{//生产者 Clerk clerk; public Producter(Clerk clerk) { super(); this.clerk = clerk; } @Override public void run() { System.out.println("生产者开始生产!"); while(true){ clerk.addProduct(); } } } class Consumer implements Runnable{//消费者 Clerk clerk; public Consumer(Clerk clerk) { super(); this.clerk = clerk; } @Override public void run() { System.out.println("消费者开始消费!"); while(true){ clerk.consumeProduct(); } } } class Clerk{//店员 int product; public Clerk(int product) { super(); this.product = product; } public static int PRODUCT=20;//最多持有产品数量 public synchronized void addProduct(){//生产产品 if(product>=PRODUCT){ try { wait(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } }else{ product++; System.out.println(Thread.currentThread().getName()+"生产了第"+product+"件产品"); notifyAll(); } } public synchronized void consumeProduct(){//消费产品 if(product<=0){ try { wait(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } }else{ product--; System.out.println(Thread.currentThread().getName()+"消费了第"+product+"件产品"); notifyAll(); } } }