Java中Thread线程总结(下)
来源:互联网 发布:mac 删除云梯 编辑:程序博客网 时间:2024/04/28 01:42
1多线程(理解)
(1)JDK5以后的针对线程的锁定操作和释放操作
Lock锁
(2)死锁问题的描述和代码体现
package day24_Thread;public class DieLock extends Thread { //定义两把锁 private static final Object objA=new Object(); private static final Object objB=new Object(); //标志位 private boolean flag; //通过传递构造参数设置标志位 public DieLock(boolean flag) { // TODO Auto-generated constructor stub this.flag=flag; } //重写run方法 @Override public void run() { // TODO Auto-generated method stub if(flag){ synchronized (objA) { System.out.println("if objA"); synchronized (objB) { System.out.println("if objB"); } } }else{ synchronized (objB) { System.out.println("else objB"); synchronized (objA) { System.out.println("else objA"); } } } }}package day24_Thread;/* * 同步的效率: * A:效率低 * B:容易产生死锁 * * 死锁: * 两个或两个以上的线程在争夺资源的过程中,发生一种相互等待的现象 * * 举例: * 中国人,美国人吃饭 * 正常情况: * 中国人:筷子两只 * 美国人:刀和叉 * * 现在: * 中国人:筷子一只,刀一把 * 美国人:筷子一只,叉一把 * */public class DieLockDemo { public static void main(String[] args) { // TODO Auto-generated method stub //创建对象 DieLock dl1 = new DieLock(true); DieLock dl2 = new DieLock(false); //启动线程 dl1.start(); dl2.start(); }}
(3)生产者和消费者多线程体现(线程间通信问题)
以学生作为资源来实现 资源类:Student 设置数据类:SetThread()生产者 获取数据类:GetThread()消费者 测试类:StudentDemo 代码: A:最基本的版本,只有一个数据 B:改进版本,给出了不同的数据,并加入了同步机制 C:等待唤醒机制改进该程序,让数据能够实现依次的出现 wait() notify() notifyAll()多生产多消费 D:等待唤醒机制的代码优化,把数据及操作都写在了资源类中。
package day24_Thread_Pro_Customer2;public class Student { //设为私有,其他成员不能直接访问 private String name; private int age; private boolean flag;//默认是没有数据,如果是true,说明有数据 //设置方法 public synchronized void set(String name,int age){ if(this.flag){ //有数据就等待 try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //没有数据就设置数据 this.name=name; this.age=age; //将标志位置为true this.flag=true; //唤醒 this.notify(); } //获取方法 public synchronized void get(){ if(!this.flag){ //没有数据就等待 try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //有数据就取数据 System.out.println(this.name+"---"+this.age); //标志位为false this.flag=false; //唤醒 this.notify(); }}package day24_Thread_Pro_Customer2;public class SetThread implements Runnable { private Student s; private int x=0; public SetThread(Student s) { // TODO Auto-generated constructor stub this.s=s; } @Override public void run() { // TODO Auto-generated method stub while(true){ //同步代码块 synchronized (s) { //没有则继续产生,执行后面代码 if(x%2==0){ s.set("林青霞", 27); }else{ s.set("刘毅", 30); } x++; } } }}package day24_Thread_Pro_Customer2;public class GetThread implements Runnable { private Student s; public GetThread(Student s) { // TODO Auto-generated constructor stub this.s=s; } @Override public void run() { // TODO Auto-generated method stub while(true){ synchronized (s) { s.get(); } } }}package day24_Thread_Pro_Customer2;/* * 分析: * 资源类:Student * 设置学生数据:SetThread(生产者) * 获取学生数据:GetThread(消费者) * 测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null -- 0 * 原因:我们在每个数据中创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个。 * * 如何实现? * 在外界把这个数据创建出来,通过构造方法传递给其他的类。(Student s) * * 问题2:为了数据的效果更好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 * A:同一个数据出现多次 * B:姓名和年龄不匹配 * 原因: * A:同一个数据出现多次 * CPU的一点点时间片的执行权,就足够你执行很多次 * B:姓名和年龄不匹配 * 线程运行的随机性 * 线程安全问题: * A:是否是多线程环境 是 * B:是否有共享数据 是 * C:是否有多条语句操作共享数据 是 * 解决方案: * 加锁 * 注意: * A:不同种类的线程都要加锁 * B:不同的线程加的锁必须是同一把锁 * * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我想依次的一次一个输出 * 如何实现呢? * 通过Java提供的等待唤醒机制解决 * * 等待唤醒: * Object类提供了三个方法: * wait():等待 * notify():唤醒单个线程 * notifyAll():唤醒所有线程 * 为什么这些方法不定义在Thread类中呢? * 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是在任意锁对象。 * 所以,这些方法必须定义在Object类中。 * * 最终版代码: * 把Student的成员变量给私有的了。 * 把设置和获取的操作给封装成了功能,并加了同步。 * 设置或者获取的线程里面值需要调用方法即可。 * */public class StudentDemo { public static void main(String[] args) { //创建资源 Student s = new Student(); //设置获取类和获取类 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //线程类 Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //启动线程 t1.start(); t2.start(); }}
(4)线程组
package day24_ThreadGroup;public class MyRunnable implements Runnable { @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } }}package day24_ThreadGroup;/* * 线程组:把多个线程组合到一起 * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制 * */public class ThreadGroupDemo { public static void main(String[] args) { // TODO Auto-generated method stub method1(); System.out.println(Thread.currentThread().getThreadGroup().getName()); //我们何如修改线程所在的组呢? //创建一个线程组 //创建其他线程的时候,把其他线程的组指定为我们自己新建的线程组 method2(); } private static void method2() { // TODO Auto-generated method stub ThreadGroup tg = new ThreadGroup("这是一个新的线程组"); MyRunnable my = new MyRunnable(); Thread t1 = new Thread(tg,my,"林青霞"); Thread t2 = new Thread(tg,my, "刘意"); System.out.println(t1.getThreadGroup().getName()); System.out.println(t2.getThreadGroup().getName()); //利用线程组统一修改该组数据 //通过组名称设置后台线程,表示该组的线程都是后台线程。 t1.setDaemon(true); } public static void method1(){ MyRunnable my = new MyRunnable(); //创建线程 Thread t1 = new Thread(my, "林青霞"); Thread t2 = new Thread(my, "刘意"); //我不知道他们属于哪个线程组,怎么办? //线程组里方法:public final ThreadGroup getThreadGroup() ThreadGroup tg1 = t1.getThreadGroup(); ThreadGroup tg2 = t2.getThreadGroup(); //线程组的方法:public final String getName() String name1=tg1.getName(); String name2=tg2.getName(); System.out.println(name1); System.out.println(name2); //通过结果我们知道了,线程默认情况下属于main线程组 }}
(5)线程池
package day24_ThreadPool;public class MyRunnable implements Runnable { @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } }}package day24_ThreadPool;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/* * 线程池的好处:线程池的每一个线程代码结束后,都不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用 * * 如何实现线程的代码呢? * A:创建一个线程池的对象,控制要创建几个线程对象 * public static ExecutorService newFixedThreadPool(int nThreads) * B:这种线程池的线程可以执行 * 可以执行Runnable对象或者Callable对象代表的线程 * 做一个类实现Runnable接口 * C:调用如下方法即可 * Future<?>submit (Runnable task) * <T> Future<T> submit(Callable<T> task) * * */public class ExecutorsDemo { public static void main(String[] args) { // TODO Auto-generated method stub //创建一个线程池对象,控制要创建几个线程对象 //public static ExecutorService newFixedThreadPool(int nThreads) ExecutorService pool = Executors.newFixedThreadPool(2); //可以执行Runable对象或者Callable对象代表的线程 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //结束线程池 pool.shutdown(); }}
(6)多线程实现的第三种方案
package day24_Callable;import java.util.concurrent.Callable;/* * 多线程求和 * */public class MyCallable implements Callable<Integer> { private int number; //通过构造方法传递number public MyCallable(int number) { // TODO Auto-generated constructor stub this.number=number; } @Override public Integer call() throws Exception { // TODO Auto-generated method stub int sum=0; for(int i=1;i<=number;i++){ sum+=i; } return sum; }}package day24_Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/* * 线程池的好处:线程池的每一个线程代码结束后,都不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用 * * 如何实现线程的代码呢? * A:创建一个线程池的对象,控制要创建几个线程对象 * public static ExecutorService newFixedThreadPool(int nThreads) * B:这种线程池的线程可以执行 * 可以执行Runnable对象或者Callable对象代表的线程 * 做一个类实现Runnable接口 * C:调用如下方法即可 * Future<?>submit (Runnable task) * <T> Future<T> submit(Callable<T> task) * */public class MyCallableDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { // TODO Auto-generated method stub //创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); //可以执行Runnable对象或者Callable对象代表的线程 Future<Integer> f1 = pool.submit(new MyCallable(100)); Future<Integer> f2 = pool.submit(new MyCallable(200)); Integer i1=f1.get(); Integer i2 = f2.get(); System.out.println("i1:"+i1); System.out.println("i2:"+i2); //结束 pool.shutdown(); }}
(7)多线程的面试题
1:多线程有几种实现方案,分别是哪几种? 一般答两种: 继承Thread类 实现Runnable接口 拓展一种:实现Callable接口,这个得和线程池结合2:同步有几种方式,分别是什么? 两种 同步代码块 同步方法3:启动一个线程是run()还是start()?它们的区别是? start() run():封装了被线程执行的代码,直接调用仅仅是普通的调用 statr():启动线程,并有jvm自动调用run()方法4:sleep()和wait()方法的区别是? sleep():必须指时间;不释放锁 wait():它可以不指定时间,也可以指定时间;释放锁5:为什么wait()、notify()、notifyAll()等方法都是定义在Object类中? 因为这些方法调用时依赖于锁对象的,而同步代码块的锁对象是任意锁 而object代表任意的对象,所以,定义在这里面。6:线程的生命周期图? 新建--就绪--运行--死亡 新建--就绪--运行--阻塞--就绪--运行--死亡 建议:画图解释
阅读全文
0 0
- Java中Thread线程总结(下)
- Java中Thread线程总结(上)
- Java Thread (线程)总结
- Java Thread 总结(线程)
- JAVA中线程Thread
- Java中的线程Thread总结
- Java中的线程Thread总结
- Java中的线程Thread总结
- Java中的线程Thread总结
- Java中的线程Thread总结
- Java中的线程Thread总结
- Java中的线程Thread总结
- Java Thread线程基础总结
- Java中线程(Thread)知识概括
- Thread学习之Java中守护线程的总结
- Java中Thread线程基础
- java 线程 总结(下)
- 总结一下java中的线程Thread
- Linux-视频监控系统(2)-Epoll的介绍及使用
- 在linux中安装cannal
- 有一种坚持,是我在学习
- ubuntu安装完成后设置root用户密码
- 解决Android中TextView单行设置过时的问题
- Java中Thread线程总结(下)
- ocr / tesseract-ocr 知识链接汇总
- 上传图片前的预览
- java反射机制调用方法及简易封装工具类
- PHP调用百度天气接口API
- 其它界面跳转到主界面,并切换主界面的Fragment
- bzoj3631[JLOI2014]松鼠的新家 树链剖分
- 初步选择一个好模型
- Codeforces 799B