zoukankan      html  css  js  c++  java
  • JAVA自学笔记23

    JAVA自学笔记23

    1、多线程
    1)引入:
    这里写图片描述
    2)进程
    是正在运行的程序。是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
    多进程:
    单进程的计算机只能做一件事情,而现在的计算机都可以做多件事情。CPU在某个时间点上只能做一件事。每一个进程都有它自己的内存空间和系统资源。
    3)多线程
    -是进程中的单个顺序控制流,是一条执行路径
    -一个进程如果只有一条执行路径,则称为单线程程序。一个进程如果有多条执行路径,称为多线程程序。
    4)并行与并发
    前者是逻辑上同时发生,指在某一个时间段内同时运行多个程序;后者是物理上同时发生,指在,某一个时间点内同时运行多个程序
    5)Java程序运行原理
    java命令会启动java虚拟机,启动jvm,等于启动了一个应用程序,也就是启动了一个进程,该进程会自动地启动一个“主线程”,然后主线程去调用某个类的main方法,所以main方法运行在主线程中。在此之前的所有程序都是单线程的。

    JVM的启动时单线程还是多线程的呢?
    多线程的。垃圾回收线程也要先启动,否则很容易出现内容溢出。最少都启动了两个线程。

    这里写图片描述
    创建新执行线程有两种方法,一种方法时将类声明为Thread的子类。该子类应重写Thread类的run方法。接下来可以分配并启动该子类的实例。
    即-自定义一个继承自Thread的类
    -重写run()方法(不是类中的所有代码都需要被线程执行。此时,为了区分哪些代码能够被执行。java提供了Thread类中的run()方法用于包含那些被执行的代码。)
    -创建对象
    -启动线程
    另一种方法是声明实现Runnable接口的类,该类然后实现run方法,然后就可以分配该类的实例。start()方法:使该线程开始执行,Java虚拟机调用该线程的run方法。它和run()的区别是run()仅仅是封装被线程执行的代码,直接调用的是普通方法start()首先启动了线程,然后再由jvm去调用该线程的run()方法。

    //多线程的实现
    //方式1
    public class MyThread extends Thread{
    public void run(){
    //一般来说,被线程执行的代码肯定是比较耗时的
    for(int x=0;x<10000;x++){
    System.out.println("cc"+x);
    }
    }
    }
    
    //测试类
    public class MyThreadDemo{
    public static void main (String[] args){
    //创建线程对象
    MyThread my1=new MyThread();
    MyThread my2=new MyThread();
    //启动线程
    my1.start();
    my2.start();
    }
    }

    5)获取和设置线程对象的名称
    获取:
    public final String getName(); //程序将输出Thread-?,?按顺序从0开始

    设置
    public final void setName(String name);

    public class MyThread extends Thread{
    //无参构造
    public MyThread(){}
    //带参构造
    public MyThread(String name){
    super(name);
    }
    public void run(){
    //一般来说,被线程执行的代码肯定是比较耗时的
    for(int x=0;x<10000;x++){
    System.out.println("getName()+cc"+x);
    }
    }
    }
    //创建线程对象
    MyThread my1=new MyThread();
    MyThread my2=new MyThread();
    //设置名称
    my1.setName("cc");
    my2.setName("dd");
    //启动线程
    my1.start();//Thread-0
    my2.start();//Thread-1
    }
    }
    
    //带参构造
    MyThread my1=new Mythread("许先生");
    MyThread my1=new Mythread("刘先生");
    
    //获取main方法对应线程的名称
    //public static Thread currentThread()
    返回当前正在执行的线程对象
    System.out.println(Thread currrentThread().getName());

    6)线程调度
    ①分时调度模型:
    所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
    ②抢占式调度模型 优先让优先级高的线程使用CPU。如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。Java使用此类模型

    设置优先级的方法:
    public final void setPriority (newPriority)
    MAX_PRIORITY=10
    MIN_PRIORITY=1
    NORM_PRIORITY=5

    获取线程对象的优先级,默认优先级是5:
    public final int getPriority()

    public class ThreadPriority extends Thread{
    public void run(){
    //一般来说,被线程执行的代码肯定是比较耗时的
    for(int x=0;x<10000;x++){
    System.out.println("getName()+cc"+x);
    }
    }
    }
    
    public class ThreadPriorityDemo{
    public static void main(String args[]){
    ThreadPriority tp1=new ThreadPriority();
    ThreadPriority tp2=new ThreadPriority();
    ThreadPriority tp3=new ThreadPriority();
    tp1.setName("aa");
    tp2.setName("bb");
    tp3.setName("cc");
    
    tp1.getPriority();
    tp2.getPriority();
    tp3.getPriority()
    
    tp1.setPriorty(8);//存在随机性
    
    
    tp1.start();
    tp2.start();
    tp3.start();
    }
    }

    7)线程控制
    线程休眠
    public static void sleep(long mills)
    在指定毫秒内让当前正在执行的线程休眠
    线程加入
    public final void join()
    等待该线程终止

    public class ThreadJoin extends Thread{
    public void run(){
    for(int x=0;x<10000;x++){
    System.out.println("getName()+cc"+x);
    }
    }
    }
    public class ThreadJoinDemo{
    public static void main(String args[]){
    ThreadJoin tp1=new ThreadJoin();
    ThreadJoin tp2=new ThreadJoin();
    ThreadJoin tp3=new ThreadJoin();
    tp1.setName("aa");
    tp2.setName("bb");
    tp3.setName("cc");
    
    tp1.start();
    tp1.join();
    tp2.start();
    tp3.start();
    }
    }

    线程礼让
    public static void yield()

    public class ThreadJoin extends Thread{
    public void run(){
    for(int x=0;x<10000;x++){
    System.out.println("getName()+cc"+x);
    Thread.yield();
    }
    }
    }
    public class ThreadYieldDemo{
    public static void main(String args[]){
    ThreadYield tp1=new ThreadYield();
    ThreadYield tp2=new ThreadYield();
    
    tp1.setName("aa");
    tp2.setName("bb");
    
    tp1.start();
    tp2.start();
    
    }
    }

    后台线程
    public final void setDaemon(boolean on)
    将该线程标记为守护线程或用户线程,当正在运行的线程都是守护线程时,jvm退出。必须在启动线程前调用。
    这里写图片描述
    中断线程
    public final void stop()//已过时但仍可使用,具有不安全性
    public void interrupt()//把线程状态终止,并抛出InterruptedException 异常

    public class ThreadStop extends Thread{
    public void run(){
    System.out.println("开始执行:"+new Date());
    }
    } 
    public class ThreadStopDemo{
    public static void main(String args[]){
    ThreadStop ts=new ThreadStop();
    ts.start();
    Thread.sleep(3000);
    //ts.stop();
    ts.intereupt();
    }
    }

    8)线程生命周期图解:
    这里写图片描述

    9)多线程的实现方案2
    ①好处:可以避免由于java单继承而带来的局限性。适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好地体现; 面向对象的设计思想。
    -自定义类MyRunnable实现Runnable接口
    -重写run()方法
    -创建MyRunnable类的对象
    -创建Thread类的对象,作为上一步骤的参数传递

    public class MyRunnable implements Runnable{
    public void run(){
    for(int x=0;x<100){
    System.out.println(Thread.currentThread.geiName()+":"+x);
    }
    }
    }
    public class MyRunnableDemo{
    public static void main(String args[]){
    MyRunnable my=new MyRunnable();
    
    //Thread t1=new Thread(my,"cc");
    //Thread t2=new Thread(my,"dd");
    Thread t1=new Thread(my);
    Thread t2=new Thread(my);
    t1.setName("cc");
    t1.setName("dd");
    t1.start();
    t2.start();
    }
    }
    

    ②两种方式的比较图解
    这里写图片描述

    @例题1:售卖电影票
    这里写图片描述

    public class SellTicketDemo{
    public static void main(String args[]){
    SellTicket st1=new SelTicket();
    SellTicket st2=new SelTicket();
    SellTicket st3=new SelTicket();
    
    st1.setName("窗口1");
    st2.setName("窗口2");
    st3.setName("窗口3");
    
    st1.start();
    st2.start();
    st3.start();
    }
    }
    
    public class SellTicket extends Thread{
    public void run(){
    private static int tickets=100;
    
    public void run(){
    while(true){
    if(tickets>0){
    System.out.println(getName()+"正在售出第"+(tickets--)+"张票");
    }
    }
    }
    }
    }
    //第二种方式
    public class SellTickets implements Runnable{
    private int tickets=100;
    public void run(){
    while(true){
    if(tickets>0){
    System.out.println(getName()+"正在售出第"+(tickets--)+"张票");
    }
    }
    }
    }
    public class void main(String args[]){
    SellTicket st=new SellTicket();
    
    Thread t1=new Thread(st,"窗口1");
    Thread t2=new Thread(st,"窗口2");
    Thread t1=new Thread(st,"窗口3");
    
    t1.start();
    t2.start();
    t3.start();
    }

    改进每次售出一张票延迟0.1秒

    //第二种方式
    public class SellTickets implements Runnable{
    private int tickets=100;
    //创建锁对象
    private Object obj =new Object();
    public void run(){
    synchronized(obj){
    while(true){
    if(tickets>0){
    Thread.sleep(1000);
    System.out.println(getName()+"正在售出第"+(tickets--)+"张票");
    }}
    }
    }
    }
    public class void main(String args[]){
    SellTicket st=new SellTicket();
    
    Thread t1=new Thread(st,"窗口1");
    Thread t2=new Thread(st,"窗口2");
    Thread t1=new Thread(st,"窗口3");
    
    t1.start();
    t2.start();
    t3.start();
    }

    出现了问题:
    ①相同号码的票售出多次
    ②出现了负数序号的票
    CPU的每一次执行必须是一个原子性(最简单基本的)操作。是由于随机性和延迟导致的
    这里写图片描述

    利用同步块的方式解决上述问题
    同步代码块:
    格式:synchronized(对象)(需要同步的代码;)
    可以解决安全问题,其对象可以是任何对象。
    把多条语句操作共享数据的部分给包起来
    同步的好处与弊端:
    好处:同步的出现解决了多线程的安全问题
    弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,非常耗费系统资源
    前提:多个线程使用同一把锁
    同步方法:把同步关键字加载到方法上
    A:同步代码块的锁对象是谁呢?
    * 任意对象。
    *
    * B:同步方法的格式及锁对象问题?
    * 把同步关键字加在方法上。
    *
    * 同步方法是谁呢?
    * this
    *
    * C:静态方法及锁对象问题?
    * 静态方法的锁对象是谁呢?
    * 类的字节码文件对象。(反射会讲)

    //再次改进
    public class SellTicketDemo {
        public static void main(String[] args) {
            // 创建资源对象
            SellTicket st = new SellTicket();
    
            // 创建三个线程对象
            Thread t1 = new Thread(st, "窗口1");
            Thread t2 = new Thread(st, "窗口2");
            Thread t3 = new Thread(st, "窗口3");
    
            // 启动线程
            t1.start();
            t2.start();
            t3.start();
        }
    }
    package cn.itcast_11;
    
    public class SellTicket implements Runnable {
    
        // 定义100张票
        private static int tickets = 100;
    
        // 定义同一把锁
        private Object obj = new Object();
        private Demo d = new Demo();
    
        private int x = 0;
    
    
        @Override
        public void run() {
            while (true) {
                if(x%2==0){
                    synchronized (SellTicket.class) {
                        if (tickets > 0) {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(Thread.currentThread().getName()
                                    + "正在出售第" + (tickets--) + "张票 ");
                        }
                    }
                }else {
    
        private static synchronized void sellTicket() {
            if (tickets > 0) {
            try {
                    Thread.sleep(100);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()
                        + "正在出售第" + (tickets--) + "张票 ");
            }
    }
    }
    

    8)线程安全的类
    StringBuffered
    Vector
    Hashtable
    collections下有很多线程安全的类

  • 相关阅读:
    OI无关 透彻随笔
    置顶帖(传送门)/to 学弟 一个菜鸡的故事
    洛谷P1494 小Z的袜子 莫队
    关于 对拍 的一些认识
    关于 带权二分/wqs二分 的一些认识
    关于 KDtree 的一些认识
    关于 网络流 的一些认识
    省选 考前模板
    关于 多项式 的一些认识/多项式入门
    小球与盒子 的奇妙关系
  • 原文地址:https://www.cnblogs.com/Tanqurey/p/10485332.html
Copyright © 2011-2022 走看看