线程
来源:互联网 发布:天刀男性捏脸数据下载 编辑:程序博客网 时间:2024/06/06 11:01
一,程序、进程和线程的区别
程序:指令集,静态的概念:
进程:操作系统 调度程序, 动态的概念。
线程:在进程内多条执行路径。
二,如何实现多线程
①继承Thread+重写run(线程体)
public class Rabbit extends Thread { @Override public void run() { //线程体 for(int i=0;i<100;i++){ System.out.println("兔子跑了"+i+"步"); } }}class Tortoise extends Thread { @Override public void run() { //线程体 for(int i=0;i<100;i++){ System.out.println("乌龟跑了"+i+"步"); } }}
//启动线程public class RabbitApp { /** * @param args */ public static void main(String[] args) { //创建子类对象 Rabbit rab = new Rabbit(); Tortoise tor =new Tortoise(); //调用start 方法 //rab.start(); //不要调用run方法 rab.run(); //tor.start(); tor.run(); for(int i=0;i<1000;i++){ System.out.println("main==>"+i); } }}
缺点:
如果我们的类已经从一个类继承了,则无法再继承Thread类。因此出现了第二种实现方式。
②通过Runnable接口实现多线程(静态代理设计模式)
步骤:
1.真实角色
2.代理角色:持有真实角色的引用
3.二者实现相同接口
例如:结婚
真实角色:你
代理:婚庆公司
接口:marry
public class StaticProxy { /** * @param args */ public static void main(String[] args) { //创建真实角色 Marry you =new You(); //创建代理角色 +真实角色的引用 WeddingCompany company =new WeddingCompany(you); //执行任务 company.marry(); }}//接口interface Marry{ public abstract void marry();}//真实角色class You implements Marry{ @Override public void marry() { System.out.println("you and 嫦娥结婚了...."); }}//代理角色class WeddingCompany implements Marry{ private Marry you; public WeddingCompany() { } public WeddingCompany(Marry you) { this.you = you; } private void before(){ System.out.println("布置猪窝...."); } private void after(){ System.out.println("闹玉兔...."); } @Override public void marry() { before(); you.marry(); after(); }}
优点:
1.避免单继承的局限性
2.便于共享资源
缺点:
不可以抛出异常也不可以有返回值,因此出现了第三种实现方式。
③通过Callable接口实现多线程
步骤:
1.创建Callable实现类+重写call()
2.借助执行调度服务ExecutorService获取future对象。
ExecutorService ser = Executors.newFixedThreadPool(num);//num
表示几个线程
Future result = ser.submit(Object);//Object表示实现类对象
3.获取值 result.get()
4.停止服务 ser.shutdownNow()
public class Call { public static void main(String[] args) throws InterruptedException, ExecutionException { //创建线程 ExecutorService ser=Executors.newFixedThreadPool(2); Race tortoise = new Race("老不死",1000); Race rabbit = new Race("小兔子",500); //获取值 Future<Integer> result1 =ser.submit(tortoise) ; Future<Integer> result2 =ser.submit(rabbit) ; Thread.sleep(2000); //2秒 tortoise.setFlag(false); //停止线程体循环 rabbit.setFlag(false); int num1 =result1.get(); int num2 =result2.get(); System.out.println("乌龟跑了-->"+num1+"步"); System.out.println("小兔子跑了-->"+num2+"步"); //停止服务 ser.shutdownNow(); }}class Race implements Callable<Integer>{ private String name ; //名称 private long time; //延时时间 private boolean flag =true; private int step =0; //步 public Race() { } public Race(String name) { super(); this.name = name; } public Race(String name,long time) { super(); this.name = name; this.time =time; } @Override public Integer call() throws Exception { while(flag){ Thread.sleep(time); //延时 step++; } return step; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getStep() { return step; } public void setStep(int step) { this.step = step; }}
三,如何停止线程
步骤:
①线程类中定义县城提使用标识
②线程体使用该标识
③对外提供方法改变标识
public class StopDemo01 { public static void main(String[] args) { Study s =new Study(); new Thread(s).start(); //外部干涉 for(int i=0;i<100;i++){ if(50==i){ //外部干涉 s.stop(); } System.out.println("main.....-->"+i); } }}class Study implements Runnable{ //1)、线程类中 定义 线程体使用的标识 private boolean flag =true; @Override public void run() { //2)、线程体使用该标识 while(flag){ System.out.println("study thread...."); } } //3)、对外提供方法改变标识 public void stop(){ this.flag =false; }}
四,线程的合并,阻塞
①join阻塞main
public class JoinDemo01 extends Thread { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { JoinDemo01 demo = new JoinDemo01(); Thread t = new Thread(demo); //新生 t.start();//就绪 //cpu调度 运行 for(int i=0;i<1000;i++){ if(50==i){ t.join(); //main阻塞... } System.out.println("main...."+i); } } @Override public void run() { for(int i=0;i<1000;i++){ System.out.println("join...."+i); } }}
②yield方法 暂停当前线程 写在哪个线程体就暂停谁
public class YieldDemo01 extends Thread { /** * @param args */ public static void main(String[] args) { YieldDemo01 demo = new YieldDemo01(); Thread t = new Thread(demo); //新生 t.start();//就绪 //cpu调度 运行 for(int i=0;i<1000;i++){ if(i%20==0){ //暂停本线程 main Thread.yield(); } System.out.println("main...."+i); } } @Override public void run() { for(int i=0;i<1000;i++){ System.out.println("yield...."+i); } }}
③sleep 间隔执行,休眠,不释放锁
1.与时间相关:倒计时
2.模拟网络延时
//倒计时public class SleepDemo01 { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { Date endTime =new Date(System.currentTimeMillis()+10*1000); long end =endTime.getTime(); while(true){ //输出 System.out.println(new SimpleDateFormat("mm:ss").format(endTime)); //等待一秒 Thread.sleep(1000); //构建下一秒时间 endTime =new Date(endTime.getTime()-1000); //10秒以内 继续 否则 退出 if(end-10000>endTime.getTime()){ break; } } } public static void test1() throws InterruptedException{ int num =10; while(true){ System.out.println(num--); Thread.sleep(1000); //暂停 if(num<=0){ break; } } }}
//模拟网络延时public class SleepDemo02 { public static void main(String[] args) { //真实角色 Web12306 web= new Web12306(); Web12306 web2 = new Web12306(); //代理 Thread t1 =new Thread(web,"路人甲"); Thread t2 =new Thread(web,"黄牛已"); Thread t3 =new Thread(web,"攻城师"); //启动线程 t1.start(); t2.start(); t3.start(); }}class Web12306 implements Runnable { private int num =50; @Override public void run() { while(true){ if(num<=0){ break; //跳出循环 } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } }}
五,关于线程的方法
- Thread.currentThread() :当前线程
- setName():设置名称
- getName():获取名称
- isAlive():判断状态
- setPriority():设置优先级
- getPriority():获取优先级
- 优先级类别:
概率,不是绝对的先后顺序
MAX_PRIORITY 10
NORM_PRIORITY 5 (默认)
MIN_PRIORITY 1
六,线程的同步
多个线程访问同一份资源—>线程安全
①同步块
synchronized(引用类型|this|类.class) {}
class Web12306 implements Runnable { private int num =10; private boolean flag =true; @Override public void run() { while(flag){ test5(); } } public void test6(){ if(num<=0){ flag=false; //跳出循环 return ; } //a b c synchronized(this){ try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //线程不安全 锁定资源不正确 public void test5(){ //a b c synchronized((Integer)num){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //锁定范围不正确 线程不安全 public void test4(){ // c 1 synchronized(this){ //b if(num<=0){ flag=false; //跳出循环 return ; } } // b try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); }//a -->1 //线程安全 锁定正确 public void test3(){ //a b c synchronized(this){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //线程不安全 public void test1(){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); }
②同步方法
public synchronized void test() {}
//线程安全 锁定正确 public synchronized void test2(){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); }
七,死锁
过多的同步会造成死锁
解决方法:生产者消费者模式(信号灯法)
步骤:
1.设置一个flag
2.
flag为T,生产者生产,消费者等待—> wait()等待,释放锁;sleep()等待,不释放锁;
生产者完成通知消费者 —>notify()/notifyAll()
flag为F,反之。
//例子:生产馒头public class TestProduce { public static void main(String[] args) { SyncStack sStack = new SyncStack(); Shengchan sc = new Shengchan(sStack); Xiaofei xf = new Xiaofei(sStack); sc.start(); xf.start(); }}class Mantou { int id; Mantou(int id){ this.id=id; }}class SyncStack{ int index=0; Mantou[] ms = new Mantou[10]; public synchronized void push(Mantou m){ while(index==ms.length){ try { this.wait(); //wait后,线程会将持有的锁释放。sleep是即使睡着也持有互斥锁。 } catch (InterruptedException e) { e.printStackTrace(); } } this.notify(); //唤醒在当前对象等待池中等待的第一个线程。notifyAll叫醒所有在当前对象等待池中等待的所有线程。 //如果不唤醒的话。以后这两个线程都会进入等待线程,没有人唤醒。 ms[index]=m; index++; } public synchronized Mantou pop(){ while(index==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notify(); index--; return ms[index]; }}class Shengchan extends Thread{ SyncStack ss = null; public Shengchan(SyncStack ss) { this.ss=ss; } @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("造馒头:"+i); Mantou m = new Mantou(i); ss.push(m); } }}class Xiaofei extends Thread{ SyncStack ss = null; public Xiaofei(SyncStack ss) { this.ss=ss; } @Override public void run() { for (int i = 0; i < 20; i++) { Mantou m = ss.pop(); System.out.println("吃馒头:"+i); } }}
八,任务调度
Time定时器类
TimeTask定时任务类(抽象类)
/** Timer() schedule(TimerTask task, Date time) schedule(TimerTask task, Date firstTime, long period) 自学 quartz */public class TimeDemo01 { public static void main(String[] args) { Timer timer =new Timer(); timer.schedule(new TimerTask(){ @Override public void run() { System.out.println("so easy...."); }}, new Date(System.currentTimeMillis()+1000), 200); }}
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 线程
- 20160821_第三周周报
- PCA降维代码
- leetcode-java-367. Valid Perfect Square
- 启动一个启动模式为singleTop的activity
- Kafka导入hdfs数据持久化
- 线程
- SpringMVC将数据显示到UI层的方法
- VS2015使用技巧 VS新建项目时 名称与解决方案名称的差别
- jq动画效果慢慢滚动到固定位置
- windows7系统的java访问VM中的ubuntu下的redis
- javascript-黑白反斗棋选关模式
- Kafka集群安装
- Android自定义View
- Linux文件的三种时间属性