多线程
来源:互联网 发布:阿里云 域名 指向淘宝 编辑:程序博客网 时间:2024/06/05 23:54
一、
1、什么是多线程程序?
有多条执行路径的程序称为多线程程序。
2、进程与线程之间的关系?
线程是依赖进程存在的,而一个线程相当于进程中的某个任务。
二、如何去实现一个多线程?
实现多线程的有关方法:
1、开始执行线程的方法:
public void start()//使用此方法要注意:线程只能启动一次,如果启动第二次会出现“线程状态异常”---IllegalThreadStateException
2、获取以及设置线程的名称:
public final String getName()//返回线程的名称public final void setName(String name)//改变线程名称,使之与参数name相同//设置线程名称的三种方法: 1)通过有参构造 2)无参+setName(String name) 3)public Thread(String name)//分配新的Thread对象
3、线程的优先级问题(注意:优先级高的线程抢占到CPU执行权的概率大,但不一定就能抢到)
public final int getPriority()//返回线程的优先级//线程的优先级有:1)public static final int MAX_PRIORITY//优先级为10,最高优先级2)public static final int MIN_PRIORITY//优先级为1,最低优先级3)public static final int NORM_PRIORITY//优先级为5,默认优先级
4、线程的等待,睡眠以及其他方法:
public final void join()//等待该线程终止 throws InterruptedExceptionpublic static void yeild()//暂停当前正在执行的线程,并执行其他线程但是并不保证另一个线程就一定能抢到执行权public static void sleep(long millis)//线程睡眠,参数为时间毫秒值 throws InterruptedExceptionpublic final void stop()//强迫线程停止public void interrupt()//中断线程的一种状态public static Thread currentThread()//返回当前正在执行的对象
有三个方法实现多线程程序:
方法一(继承自Thread类):
步骤:1.自定义一个类使其继承自Thread类;
2·在自定义的类中重写Thread类中的run()方法;(run()中心写的是一些耗时的代码:例如循环语句,线程睡眠,线程等待)
3·在主线程中创建自定义类的实例;
4·启动线程;
具体程序实现如下:
//子线程:package _14.homework;public class SetDemo extends Thread { @Override public void run() { for (int x = 0; x < 200; x++) System.out.println(x); }}//主线程:package _14.homework;public class Demo3 { public static void main(String[] args){ SetDemo st1=new SetDemo(); SetDemo st2=new SetDemo(); st1.start(); st2.start(); }}
方法二(实现Runnable接口):
步骤:1·自定义一个类并使其实现Runnable接口;
2·在自定义类中重写该接口的run()方法;
3·在主线程中创建自定义类的实例对象;
4·创建Thread类对象将自定类的实例对象作为参数进行传递;
5·分别启动线程;
具体代码实现如下:
//子线程:package _14.homework;public class ThreadDemo implements Runnable { @Override public void run() { for (int x = 0; x < 200; x++) { System.out.println(x); } }}//主线程:package _14.homework;public class Demo4 { public static void main(String[] args) { ThreadDemo td1 = new ThreadDemo(); ThreadDemo td2 = new ThreadDemo(); Thread t1 = new Thread(td1); Thread t2 = new Thread(td2); t1.start(); t2.start(); }}
方法三(实现Callable接口)
步骤:1·自建一个类实现Callable接口;
2·利用工厂类创建线程池对象;
3·提交Callable任务;
4·结束线程池;
具体代码实现如下:
//子线程:package _14.homework;import java.util.concurrent.Callable;public class CallableDemo implements Callable<Object> { @Override public Object call() throws Exception { for (int x = 0; x < 200; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } return null; }}//主线程:package _14.homework;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test { public static void main(String[] args) { ExecutorService threadPool = Executors.newFixedThreadPool(3); threadPool.submit(new CallableDemo()); threadPool.submit(new CallableDemo()); threadPool.submit(new CallableDemo()); threadPool.shutdown(); }}
三、如何设置一个守护线程?(注意:当正在运行的线程都是守护线程时,Java虚拟机退出并且设置守护线程的方法必须在线程启动前调用!)
public final void setDaemon(boolean on)//若将on设置为true,则将一个线程设置为了守护线程;
具体代码实现如下:
//子线程:package _14.homework;public class ThreadDemo2 extends Thread { @Override public void run() { for(int x=0;x<100;x++){ System.out.println(getName()+": "+x); } }}//主线程:package _14.homework;public class Test2 { public static void main(String[] args){ ThreadDemo2 td1=new ThreadDemo2(); ThreadDemo2 td2=new ThreadDemo2(); td1.setName("老二"); td2.setName("老三"); td1.setDaemon(true); td2.setDaemon(true); td1.start(); td2.start(); Thread.currentThread().setName("老大"); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+": "+i); } }}
由于上面的方式存在安全性问题,我们怎么检验该多线程是否安全?
三个标准:1.是否是多线程环境;
2.是否有共享数据;
3.是否有多条语句对共享数据进行操作;
四、同步机制:
既然存在安全问题我们如何去解决这些安全问题呢?
解决的方式就是同步机制!
首先同步锁:
同步代码块:synchronized(同步锁对象){ //对共享数据进行操作的多条代码 } //同步锁对象可以是Object类以及任意的Java类
具体代码实现如下:
//子线程:package _14.homework;public class SellTicketDemo implements Runnable { public static int tickets = 100; private Object obj = new Object(); @Override public void run() { while (true) { synchronized (obj) { if (tickets > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "出售: 第 " + (tickets--) + " 张票"); } } } }}//主线程:package _14.homework;public class SellTicket { public static void main(String[] args){ SellTicketDemo std=new SellTicketDemo(); Thread t1=new Thread(std,"窗口1"); Thread t2=new Thread(std,"窗口2"); Thread t3=new Thread(std,"窗口3"); t1.start(); t2.start(); t3.start(); }}
同步方法(如果一个方法进来之后就是同步代码块,那么就可以将其改进为同步方法):
非静态的同步方法的锁对象为Object类以及任意的Java类型对象!
而静态的同步方法的锁对象则是当前类名的class属性:即类名.class
//子线程:package _14.homework;public class SellTicketDemo implements Runnable { public static int tickets = 100; private int x; @Override public void run() { while (true) { if (x % 2 == 0) { synchronized (SellTicketDemo.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售: 第 " + (tickets--) + " 张票"); } } }else{ sellTicketDemo(); } x++; } } public static synchronized void sellTicketDemo(){ if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售: 第 " + (tickets--) + " 张票"); } }}//主线程:package _14.homework;public class SellTicket { public static void main(String[] args){ SellTicketDemo std=new SellTicketDemo(); Thread t1=new Thread(std,"窗口1"); Thread t2=new Thread(std,"窗口2"); Thread t3=new Thread(std,"窗口3"); t1.start(); t2.start(); t3.start(); }}
五、等待唤醒机制:
利用同步机制我们解决了上面的线程安全问题,但执行的结果有可能出现死锁以及结果是一段一段的相同的结果,那么怎样可以让执行结果变为一个线程执行完一次,另一个线程开始执行呢?采用等待唤醒机制!
具体代码实现如下:
//学生类:package _14.homework;public class Student2 { String name; int age ; String sex; boolean flag ;}//生产者线程:package _14.homework;public class SetDemo1 implements Runnable { private int x = 0; private Student2 s; public SetDemo1(Student2 s) { this.s = s; } @Override public void run() { while (true) { synchronized (s) { if (s.flag) { try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if (x % 2 == 0) { s.name = "张三"; s.age = 30; s.sex = "男"; } else { s.name = "翠花"; s.age = 26; s.sex = "女"; } x++; s.flag = true; s.notify(); } } }}//消费者线程:package _14.homework;public class GetThread2 implements Runnable { private Student2 s; public GetThread2(Student2 s) { this.s = s; } @Override public void run() { while(true){ synchronized (s) { if(!s.flag){ try { s.wait() ; } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(s.name + "------" + s.age+"------"+s.sex); s.flag = false ; s.notify() ; } } }}//主线程:package _14.homework;public class StudentDemo2 { public static void main(String[] args) { Student2 s = new Student2() ; SetDemo1 sd = new SetDemo1(s) ; GetThread2 gt = new GetThread2(s) ; Thread t1 = new Thread(sd) ; Thread t2 = new Thread(gt) ; t1.start() ; t2.start() ; } }
六、线程组:
有关线程组的一些方法:
public class ThreadGroup{}//多个线程的集合public final String getName() //返回线程组名称public final TreadGroup getThreadGroup()//返回该线程所在线程组public ThreadGroup(String name)//构造一个新的线程组public Thread(ThreadGroup group,Runnable target,String name)public final void setDaemon(boolean daemon)//更改线程组的后台程序状态//如果将参数设置为true则是将线程组中的所有子线程都设置为了守护线程
七、线程池(当程序中要大量创建生存期很短的线程时,最好考虑线程池):当启动线程完毕后,不会被垃圾回收器回收而是又回到线程池中变成空闲状态!
创建线程池的方法:
public static ExecutorService newCachedPool()//创建一个根据需要创建新线程的线程池public static ExecutorService newFixedThreadPool(int nThread)//创建一个可重用固定线程数的线程池public static ExecutorService newSingleThreadExecutor()
关闭线程池的方法:
void shutdowm();//关闭线程池<T>Future<T>submit(Callable <T> task)//提交一个任务用于执行Future<?>submit(Runnable task)//提交一个Runnable任务用于执行
具体实现即为多线程实现的第三种方式;
八、定时器Timer类
定时器的具体方法:
public void schedule(TimerTask task,ling delay)//安排在指定的时间执行public void schedule(TimerTask task,long delay,long period)//安排在指定延迟后执行指定任务public void cancel()//指定在多少毫秒后每period毫秒重复执行
TimerTask需要被执行的任务类是一个抽象类不能直接实例化
具体代码实现如下:
//package _14.homework;import java.util.Timer;public class TimerDemo { public static void main(String[] args){ Timer t = new Timer() ; t.schedule(new MyTask(),3000,1000 ); }}
package _14.homework;import java.util.TimerTask;class MyTask extends TimerTask{ @Override public void run() { System.out.println("世界如此美好,"); System.out.println("你却如此暴躁,"); System.out.println("这样不好!"); System.out.println("不好!!!"); System.out.println(); }}
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- javascript中不常见的运算符
- Android四大组件详细介绍及例子
- Java学习19 应用程序国际化
- Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Con
- 使用VS2015打包winform程序安装包简单方法(不需要InstallShield)
- 多线程
- chapter9.6
- 【干货】快速安装 GitLab 并汉化
- iis6导出Excel报错检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败,8000401a错误解决办法
- OpenGL Depth and Stencil Test
- mysql主从配置
- 猴子偷桃问题
- 【keil uvision4】 Debug系列
- spring boot--使用异步请求,提高系统的吞吐量