javaSE每天练程序——day18线程之间等待唤醒,内存可见性,解决原子性,线程的五大状态,三种线程池,定时器,单例模式

编程入门 行业动态 更新时间:2024-10-08 22:17:56

javaSE每天练程序——day18<a href=https://www.elefans.com/category/jswz/34/1771240.html style=线程之间等待唤醒,内存可见性,解决原子性,线程的五大状态,三种线程池,定时器,单例模式"/>

javaSE每天练程序——day18线程之间等待唤醒,内存可见性,解决原子性,线程的五大状态,三种线程池,定时器,单例模式

学习目录:

Lock锁
死锁现象
线程池
定时器
设计模式

线程间的等待唤醒机制

线程协作

线程通信

应用场景 : 生产者和消费者问题
假设仓库中只能存放一件产品 , 生产者将生产出来的产品放入仓库 , 消费者将仓库中产品取走消费 .
如果仓库中没有产品 , 则生产者将产品放入仓库 , 否则停止生产并等待 , 直到仓库中的产品被消费者取走为止 .
如果仓库中放有产品 , 则消费者可以将产品取走消费 , 否则停止消费并等待 ,直到仓库中再次放入产品为止 .

1.定义一个资源
2.生产线程
3.消费线程
4.测试类

  • 这时候产生了线程安全问题
    1.多线程环境
    2.共享数据
    3.多个语句操控这个共享数据

  • 唤醒机制的4个方法
    Object类中

  • sleep和wait的区别:
    相同:同样是让线程处于阻塞状态
    不同:sleep需要设定睡眠时间,一旦休眠不释放锁
    wait:可以设定也可以不设定睡眠时间,一旦休眠释放锁

案例一:生产消费的关系

package javaSEreview20190730.线程之间的等待唤醒机制;/*** @Description:TODO* @Author:@李小白* @Date:2019/7/30 22:30*/
public class MyTest {public static void main(String[] args) {Student student = new Student();SetThread setStudent = new SetThread(student);GetThread getStudent = new GetThread(student);setStudent.start();getStudent.start();}
}
package javaSEreview20190730.线程之间的等待唤醒机制;/*** @Description:TODO* @Author:@李小白* @Date:2019/7/30 22:29*/
public class Student {public String name;public int age;public boolean flag=false; //定义一个标记,默认是没有资源了
}
package javaSEreview20190730.线程之间的等待唤醒机制;/*** @Description:TODO* @Author:@李小白* @Date:2019/7/30 22:29*/
public class SetThread extends Thread{Student student;int i=0;public SetThread(Student student) {this.student=student;}@Overridepublic void run() {while (true) {synchronized (student){//加把锁,防止数据出现错误if (student.flag) {//对于生产者来说,没有资源的就要等待try {student.wait();} catch (InterruptedException e) {e.printStackTrace();}}if (i%2==0) {student.name="张三";student.age=23;}else {student.name="李四";student.age=24;}//通知消费线程去消费student.flag=true;//修改标志student.notify();//唤醒消费线程,唤醒之后,多个线程再次开始争抢时间片i++;}}}
}
package javaSEreview20190730.线程之间的等待唤醒机制;/*** @Description:TODO* @Author:@李小白* @Date:2019/7/30 22:30*/
public class GetThread extends Thread {Student student;public GetThread(Student student) {this.student=student;}@Overridepublic void run() {while (true) {//消费线程来一个循环进行接收synchronized (student){if (!student.flag) {//如果消费线程没有资源的话就要等待try {student.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果有资源的话就输出,消费了线程就要通知生产线程去生产System.out.println(student.name+"-----"+student.age);student.flag=false;//改变标记student.notify();//唤醒生产线程}}}
}

多线程(解决内存可见性问题 volatile)(了解)

java内存模型?
  • java的内存模型规定了多有的变量都分配在主存中,但每个线-程都要有自己的工作内存

  • 线程工作内存中所使用到的的变量都是从主存中copy的

  • 线程对所有变量的操作(读取,赋值)必须在工作内存中进行

  • 不同线程之间无法直接访问对方的对方工作内存,线程之间变量的传递都是通过主存来完成的

可见性问题?
  • java提供了volatile关键字
  • 在一个共享变量前加上volatile修饰,他会保证工作内存中修改的值会立即保存到主存中,其他变量读取到的是最新的值,保证变量不会出错.
  • 不加的话,其他线程读取的不是最新的变量,保证不了可见性
  • synchronized和Lock也能够保证可见性,效率太低,他只可以同一个时刻保证一个线程获取锁,然后执行同步代码,在释放锁之前将变量刷新到主存中
volatile 关键字
  • 当多个线程进行操作共享数据时,可以保证内存中的数据可见。
    相较于 synchronized 是一种较为轻量级的同步策略。
  • 但是volatile与其他的锁不同的是
     对于多线程,不是一种互斥关系
     不能保证变量状态的“原子性操作”

案例一:解决内存可见性问题

package javaSEreview20190730.解决内存可见性问题;/*** @Description:TODO* @Author:@李小白* @Date:2019/7/30 23:16*/
public class Demo01 {public static void main(String[] args) {MyRunable myRunable = new MyRunable();new Thread(myRunable).start();while (true) {if (myRunable.getflag()){System.out.println("进来了");break;}}}
}
class MyRunable implements Runnable{volatile boolean flag=false;//解决内存可见性问题public boolean getflag(){return flag;}@Overridepublic void run() {try {Thread.sleep(10);//手动制作一个网络延迟} catch (InterruptedException e) {e.printStackTrace();}flag=true;System.out.println("flag的值是"+getflag());}
}

多线程(CAS 算法)(了解)解决原子性

  • 原子性?
    不可再被分割
    i++不是原子性
  • CAS算法?
    是一种硬件对并发的支持,解决效率低下的原子性
    是一种无锁的非阻塞算法的实现。
    jdk5增加了并发包java.util.concurrent.*,区别乐观锁(volatile和CAS算法,无互斥性)和悲观锁(synchronized,有互斥性一个线程必须操作完)
    案例一:解决原子性
package javaSEreview20190730.解决原子性问题;import java.util.concurrent.atomic.AtomicInteger;/*** @Description:TODO* @Author:@李小白* @Date:2019/7/31 0:03*/
public class Demo {public static void main(String[] args) {MyRunable myRunable = new MyRunable();for (int i = 0; i < 10; i++) {new Thread(myRunable).start();}}
}
class MyRunable implements Runnable{//保证了原子性,   把普通变量换成原子变量,AtomicInteger atomicInteger= new AtomicInteger(1);@Overridepublic void run() {while (true){try {Thread.sleep(100);//给一个网络议延时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"----"+atomicInteger.getAndIncrement());}}
}

线程的五大状态

匿名内部类的开启线程

package javaSEreview20190730.匿名内部类开启线程;/*** @Description:匿名内部类开启线程* @Author:@李小白* @Date:2019/7/31 0:21*/
public class Demo {public static void main(String[] args) {//方式一:第一种方式new Thread(){@Overridepublic void run() {System.out.println("方式一的第一种方式执行了");}}.start();Thread th=new Thread() {@Overridepublic void run() {System.out.println("线程执行了");}};th.start();//方式二:new Thread(new Runnable(){@Overridepublic void run() {System.out.println("第二种方式执行了");}}).start();}
}

线程池

  • 定义:一个装有一定线程对象的容器djk5之后出现线程池
  • 因:手创建线程耗费资源,循环后死亡
    虽然线程是轻量级的但是多线程的开启让服务器受不了
    多线程之间的切换让cpu受不了
    所以需要一个少线程,cpu繁忙的线程池
JDK5新增了一个Executors工厂类来产生线程池

方法:
Executors.下面的三个方法
public static ExecutorService newCachedThreadPool(): 根据任务的数量来创建线程对应的线程个数
submit()创建线程
shutdown()关闭线程
public static ExecutorService newFixedThreadPool(int nThreads): 固定初始化几个线程
public static ExecutorService newSingleThreadExecutor(): 初始化一个线程的线程池

案例一:方法一应用

package day20190801.线程池;import day20190728.study01.线程的创建方式二.Runables;/*** @description:* @author: @李小白* @create: 2019-08-01 10:18*/
public class MyRunable extends Runables {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"线程执行了");}
}
package day20190801.线程池;import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** @description: 线程池,根据任务的个数来创建线程的个数,可以创建多个线程池* @author: @李小白* @create: 2019-08-01 10:19*/
public class CachedThreadPoll {public static void main(String[] args) {ExecutorService cachedThreadPool = Executors.newCachedThreadPool();//选择创建多个线程,和任务相匹配的多个线程Future<?> submit = cachedThreadPool.submit(new MyRunable());//新建线程Future<?> submit2 = cachedThreadPool.submit(new MyRunable());//新建线程Future<?> submit3 = cachedThreadPool.submit(new MyRunable());//新建线程Future<?> submit4 = cachedThreadPool.submit(new MyRunable());//新建线程cachedThreadPool.shutdown();//关闭线程池}
}

案例二:方法二应用

MyRunable方法不变 
package day20190801.线程池;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** @description: 创建指定的线程的个数* @author: @李小白* @create: 2019-08-01 10:29*/
public class FixedThreadPoll {public static void main(String[] args) {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);//指定了3个线程Future<?> submit = fixedThreadPool.submit(new MyRunable());Future<?> submit2 = fixedThreadPool.submit(new MyRunable());Future<?> submit3 = fixedThreadPool.submit(new MyRunable());fixedThreadPool.shutdown();//关闭线程池}
}

案例三:方法三的应用

MyRunable不变
package day20190801.线程池;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** @description: 只有一个而单独的线程* @author: @李小白* @create: 2019-08-01 10:34*/
public class SigleThreadPool {public static void main(String[] args) {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();Future<?> submit = singleThreadExecutor.submit(new MyRunable());singleThreadExecutor.shutdown();}
}

案例四:
用Callbale的方式执行线程池

package day20190801.线程池;import java.util.concurrent.Callable;/*** @description: 第三种方式* @author: @李小白* @create: 2019-08-01 10:57*/
public class MyCallable implements Callable<Integer> {int num;int sum=0;public MyCallable(int num){this.num=num;}@Overridepublic Integer call() throws Exception {for (int i = 0; i < num; i++) {sum+=i;}return sum;}
}
package day20190801.线程池;import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** @description:* @author: @李小白* @create: 2019-08-01 10:58*/
public class MyCallableDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);MyCallable myCallable = new MyCallable(10);//指定10个任务Future<Integer> submit = fixedThreadPool.submit(myCallable);Integer integer = submit.get();System.out.println(integer);MyCallable myCallable2 = new MyCallable(100);//指定10个任务Future<Integer> submit2 = fixedThreadPool.submit(myCallable2);Integer integer2 = submit.get();//获取线程执行完之后的返回结果System.out.println(integer2);}
}

多线程(定时器的概述和使用)(理解)

  • 概念:调度多个执行任务以后台执行的方式执行的方式执行
  • 在Java中,可以通过Timer和TimerTask类来实现定义调度的功能。
    Timer:
    public Timer()
    public void schedule(TimerTask task, long delay):
    public void schedule(TimerTask task,long delay,long period);
    public void schedule(TimerTask task, Date time):
    public void schedule(TimerTask task, Date firstTime, long period):
    TimerTask:定时任务
    public abstract void run()//继承TimerTask后写的run
    public boolean cancel()//直接取消定时器
    案例一:
    定时关机
package day20190801.定时器;import sun.awt.TimedWindowEvent;import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;/*** @description: 定时关机* @author: @李小白* @create: 2019-08-01 11:16*/
public class Demo1定时关机 {public static void main(String[] args) throws ParseException {Runtime runtime = Runtime.getRuntime();Timer timer = new Timer();String data="2019-08-01 11:31:00";timer.schedule( new TimerTask() {@Overridepublic void run() {try {runtime.exec("shutdown -s -t 0");//定时关机的Dos命令} catch (IOException e) {e.printStackTrace();}}},new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(data));}
}

案例二:方法三和方法四
删库跑路

package day20190801.定时器;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;/*** @description: 在指定的日期进行删库跑路* @author: @李小白* @create: 2019-08-01 11:24*/
public class Demo02删库跑路 {public static void main(String[] args) throws ParseException {Timer timer = new Timer();String data="2019-08-01 11:31:00";SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date parse = simpleDateFormat.parse(data);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("删库跑路");}},parse);}
}

案例三:
定时删除文件夹

package day20190801.定时器;import java.io.File;
import java.util.Timer;
import java.util.TimerTask;/*** @description:* @author: @李小白* @create: 2019-08-01 11:34*/
public class MyTimerTask03 extends TimerTask {Timer timer;public MyTimerTask03(Timer timer){this.timer=timer;}@Overridepublic void run() {File file = new File("D:\\图片");getDelete(file);}private void getDelete(File file) {File[] files = file.listFiles();file.delete();//如果是空文件就直接删除for (File f : files) {if (f.isFile()){f.delete();}else {getDelete(f);}}}
}
package day20190801.定时器;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;/*** @description:* @author: @李小白* @create: 2019-08-01 11:33*/
public class Demo03定时删除文件夹 {public static void main(String[] args) throws ParseException {Timer timer = new Timer();String data="2019-08-01 11:31:00";Date simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(data);MyTimerTask03 myTimerTask1 = new MyTimerTask03(timer);timer.schedule(myTimerTask1,simpleDateFormat);}
}

案例五:方法一和方法二的应用
连环爆炸

package day20190801.定时器;import java.util.Timer;
import java.util.TimerTask;/*** @description:* @author: @李小白* @create: 2019-08-01 11:12*/
public class Demo04连环爆 {public static void main(String[] args) {Timer timer = new Timer();TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.out.println("爆炸了!!!!");}};//2秒后爆炸timer.schedule(timerTask,1000,2000);//间隔1000毫秒就爆炸一下
//        timer.cancel();//直接就取消定时}
}

多线程(多线程常见的面试题)(理解

A:多线程有几种实现方案,分别是哪几种? 三种
B:同步有几种方式,分别是什么? 三种 同步代码块 同步方法,Lock
C:启动一个线程是run()还是start()?它们的区别?

设计模式(设计模式的概述和分类)(了解)

单例设计模式:单例:在内存中,只存在该类的一个对象
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编写、代码设计经验的总结。

使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性以及代码的结构更加清晰.
B:设计模式分类
创建型模式(创建对象的): 单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
行为型模式(对象的功能): 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
结构型模式(对象的组成): 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

设计模式(单例模式之懒汉式、饿汉式)(掌握)

饿汉式和懒汉式的区别:
开发中 饿汉式
面试中 懒汉式
面试的两种思想
线程安全思想
延迟加载思想

案例一:
饿汉式

package day20190801.单例模式;/*** @description:* @author: @李小白* @create: 2019-08-01 13:44*/
public class Student {private static Student student=null;public Student() {}public synchronized static Student getStudent(){if (student==null){Student student = new Student();}return student;}
}
package day20190801.单例模式;import com.sun.xml.internal.ws.util.pipe.DumpTube;/*** @description:汉模式* @author: @李小懒白* @create: 2019-08-01 13:46*/
public class Demo01 {public static void main(String[] args) {Student student = Student.getStudent();Student student1 = Student.getStudent();System.out.println(student.equals(student1));}
}

案例二:
懒汉式:

package day20190801.单例模式;/*** @description:* @author: @李小白* @create: 2019-08-01 14:22*/
public class Teacher {public static Teacher teacher=new Teacher();public Teacher() {}public static Teacher getTeacher(){return teacher;}
}
package day20190801.单例模式;/*** @description:* @author: @李小白* @create: 2019-08-01 14:22*/
public class Demo02 {public static void main(String[] args) {Teacher teacher = Teacher.getTeacher();Teacher teacher2 = Teacher.getTeacher();System.out.println(teacher.equals(teacher2));}
}

更多推荐

javaSE每天练程序——day18线程之间等待唤醒,内存可见性,解决原子性,线程的五大状态,三种线程池,定时器,单例模式

本文发布于:2024-02-27 19:16:40,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1765784.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   定时器   三种   五大   原子

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!