多线程基础1-线程2种方式、2方式实现购票、join、yield
2017-12-17 10:55
549 查看
继承Thread创建线程
实现Runnable创建线程
继承Thread实现购票
实现Runnable实现购票
主线程在执行到i=7时候,如果子线程任务没有执行完毕,那么子线程join进来,执行完毕子线程代码,在继续执行主线程代码,所以子线程执行任务完毕之后,才执行主线程i=8的操作
因为主线程在i=2时候,交出执行权限,然后主线程、子线程继续抢夺cpu执行权限,上面的例子就是主线程yield交出cpu执行权限,由子线程抢夺
下面的例子就是主线程在yield交出cpu执行权限,再次有主线程获取
或者如下的效果
输出如下:
需要注意的是在run方法中,使用共享的静态变量,这个方法其实也不能完全解决数据共享的问题,因为可能某一个线程拿到火车票了,例如票号10,然后去执行–操作,在这个–操作还没执行完,另外一个线程也拿到共享数据了,此刻依然是没有进行减少操作完毕之前的10,所以就造成如下的结果,打印重票错票
如果改成int ticket = 10;就是开了3个线程,每个线程有自己的变量,而非static共享的变量,所以每个线程会输出10长票
看看是如何输出的
利用实现的方式实现购票,同理一样,但是static int ticket = 10;跟int ticket = 10;写法都行,但是都会出现重票错票
输出如下:
实现Runnable创建线程
继承Thread实现购票
实现Runnable实现购票
继承Thread创建线程
package safly; /* * Thread的常用方法: * 1.start():启动线程并执行相应的run()方法 * 2.run():子线程要执行的代码放入run()方法中 * 3.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(int newPriority) :改变线程的优先级 */ class SubThread extends Thread { public void run() { for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i); } } } public class Demo { public static void main(String[] args) { SubThread st1 = new SubThread(); st1.setName("子线程1"); st1.start(); Thread.currentThread().setName("========主线程"); for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i); if(i % 2 == 0){ Thread.currentThread().yield(); } if(i == 7){ try { st1.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } System.out.println(st1.isAlive()); } }
========主线程:5:1 子线程1:5:1 ========主线程:5:2 子线程1:5:2 ========主线程:5:3 子线程1:5:3 ========主线程:5:4 子线程1:5:4 子线程1:5:5 ========主线程:5:5 ========主线程:5:6 子线程1:5:6 ========主线程:5:7 子线程1:5:7 子线程1:5:8 子线程1:5:9 子线程1:5:10 ========主线程:5:8 ========主线程:5:9 ========主线程:5:10 false
主线程在执行到i=7时候,如果子线程任务没有执行完毕,那么子线程join进来,执行完毕子线程代码,在继续执行主线程代码,所以子线程执行任务完毕之后,才执行主线程i=8的操作
因为主线程在i=2时候,交出执行权限,然后主线程、子线程继续抢夺cpu执行权限,上面的例子就是主线程yield交出cpu执行权限,由子线程抢夺
下面的例子就是主线程在yield交出cpu执行权限,再次有主线程获取
或者如下的效果
========主线程:5:1 ========主线程:5:2 ========主线程:5:3 ========主线程:5:4 子线程1:5:1 子线程1:5:2 子线程1:5:3 子线程1:5:4 ========主线程:5:5 子线程1:5:5 子线程1:5:6 子线程1:5:7 子线程1:5:8 子线程1:5:9 子线程1:5:10 ========主线程:5:6 ========主线程:5:7 ========主线程:5:8 ========主线程:5:9 ========主线程:5:10 false
实现Runnable创建线程
package safly; /* * 创建多线程的方式二:通过实现的方式 * * 对比一下继承的方式 vs 实现的方式 * 1.联系:public class Thread implements Runnable * 2.哪个方式好?实现的方式优于继承的方式 * why? ① 避免了java单继承的局限性 * ② 如果多个线程要操作同一份资源(或数据),更适合使用实现的方式 */ //1.创建一个实现了Runnable接口的类 class PrintNum1 implements Runnable { //2.实现接口的抽象方法 public void run() { // 子线程执行的代码 for (int i = 1; i <= 10; i++) { if (i % 2 == 0) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class Demo { public static void main(String[] args) { //3.创建一个Runnable接口实现类的对象 PrintNum1 p = new PrintNum1(); //要想启动一个多线程,必须调用start() //4.将此对象作为形参传递给Thread类的构造器中,创建Thread类的对象,此对象即为一个线程 Thread t1 = new Thread(p); //5.调用start()方法:启动线程并执行run() t1.start();//启动线程;执行Thread对象生成时构造器形参的对象的run()方法。 //再创建一个线程 Thread t2 = new Thread(p); t2.start(); } }
输出如下:
Thread-0:2 Thread-1:2 Thread-0:4 Thread-1:4 Thread-0:6 Thread-1:6 Thread-0:8 Thread-0:10 Thread-1:8 Thread-1:10
继承Thread实现购票
package safly; //模拟火车站售票窗口,开启三个窗口售票,总票数为100张 //存在线程的安全问题 class Window extends Thread { static int ticket = 10; public void run() { while (true) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "售票,票号为:" + ticket--); } else { break; } } } } public class Demo { public static void main(String[] args) { 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(); } }
需要注意的是在run方法中,使用共享的静态变量,这个方法其实也不能完全解决数据共享的问题,因为可能某一个线程拿到火车票了,例如票号10,然后去执行–操作,在这个–操作还没执行完,另外一个线程也拿到共享数据了,此刻依然是没有进行减少操作完毕之前的10,所以就造成如下的结果,打印重票错票
窗口3售票,票号为:10 窗口2售票,票号为:9 窗口1售票,票号为:10 窗口2售票,票号为:7 窗口3售票,票号为:8 窗口2售票,票号为:5 窗口1售票,票号为:6 窗口1售票,票号为:2 窗口2售票,票号为:3 窗口3售票,票号为:4 窗口1售票,票号为:1
如果改成int ticket = 10;就是开了3个线程,每个线程有自己的变量,而非static共享的变量,所以每个线程会输出10长票
看看是如何输出的
窗口3售票,票号为:10 窗口2售票,票号为:10 窗口1售票,票号为:10 窗口2售票,票号为:9 窗口3售票,票号为:9 窗口2售票,票号为:8 窗口1售票,票号为:9 窗口2售票,票号为:7 窗口2售票,票号为:6 窗口3售票,票号为:8 窗口2售票,票号为:5 窗口2售票,票号为:4 窗口3售票,票号为:7 窗口3售票,票号为:6 窗口3售票,票号为:5 窗口3售票,票号为:4 窗口1售票,票号为:8 窗口1售票,票号为:7 窗口1售票,票号为:6 窗口3售票,票号为:3 窗口2售票,票号为:3 窗口3售票,票号为:2 窗口1售票,票号为:5 窗口3售票,票号为:1 窗口2售票,票号为:2 窗口2售票,票号为:1 窗口1售票,票号为:4 窗口1售票,票号为:3 窗口1售票,票号为:2 窗口1售票,票号为:1
实现Runnable实现购票
package safly; //使用实现Runnable接口的方式,售票 /* * 此程序存在线程的安全问题:打印车票时,会出现重票、错票 */ class Window1 implements Runnable { static int ticket = 10; //int也可以 // int ticket = 10; public void run() { while (true) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "售票,票号为:" + ticket--); } else { break; } } } } public class Demo { public static void main(String[] args) { Window1 w = new Window1(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }
利用实现的方式实现购票,同理一样,但是static int ticket = 10;跟int ticket = 10;写法都行,但是都会出现重票错票
输出如下:
窗口1售票,票号为:10 窗口3售票,票号为:9 窗口3售票,票号为:7 窗口2售票,票号为:9 窗口3售票,票号为:6 窗口3售票,票号为:4 窗口1售票,票号为:8 窗口3售票,票号为:3 窗口3售票,票号为:1 窗口2售票,票号为:5 窗口1售票,票号为:2
相关文章推荐
- JAVA基础再回首(二十四)——多线程的概述、实现方式、线程控制、生命周期、多线程程序练习、安全问题的解决
- Java_基础—多线程(匿名内部类实现线程的两种方式和设置名字的方法)
- java多线程基础(5)-调度方式之暂停当前线程方式4-连接线程(join)
- 复习基础-JAVA多线程,基于Condition实现子线程、主线程顺序处理
- Java多线程基础学习之线程的创建方式总结
- java多线程基础(3)-调度方式之暂停当前线程方式2-放弃
- 多线程之创建线程的方式之一:实现Callable接口(三)
- 黑马程序员_笔记_多线程(创建线程的第二种方式:实现Runable接口)
- 线程的2种实现方式
- java多线程 -- 创建线程的第三者方式 实现Callable接口
- JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)
- 用java传统线程方式实现多线程轮询执行问题
- Java【多线程知识总结(5)】比较继承Thread类创建线程和实现Runnable接口创建线程这两种方式
- java 多线程系列基础篇(九)之interrupt()和线程终止方式
- Java并发编程基础---(14)实现多线程的3种方式
- 多线程的深入学习:单生产单消费,单生产多消费,多生产多消费,守护线程,线程优先级,join和yield,线程内部匿名类
- Java【多线程知识总结(5)】比较继承Thread类创建线程和实现Runnable接口创建线程这两种方式
- 多线程之创建线程的方式之一:实现Callable接口(三)
- java 多线程(2) 线程的调度和优先级 / sleep() / interrupt() 打断join() / yield() / setPriority()
- 多线程—04—守护线程、interrupt、join、yield、线程优先级