zoukankan      html  css  js  c++  java
  • 线程

    后台线程

    在Java程序中,只要前台有一个线程在运行,则整个java进程都不会消失,所以此时可以设置一个后台线程,

    这样即使Java进程结束了,此后台线程依然会继续执行。要想实现这样的操作,直接使用setDaemon()方法即可。

    礼让yield

    public class ThreadYield implements Runnable {
    
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
                if(i==3){
                    Thread.currentThread().yield();//当前线程礼让
                }
            }
    
        }
        public static void main(String[] args) {
            ThreadYield ty =new ThreadYield();
            Thread t1 = new Thread(ty, "A");
            t1.start();
            Thread t2 = new Thread(ty, "B");
            t2.start();
        }
    
    }public class ThreadYield implements Runnable {
    
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
                if(i==3){
                    Thread.currentThread().yield();//当前线程礼让
                }
            }
    
        }
        public static void main(String[] args) {
            ThreadYield ty =new ThreadYield();
            Thread t1 = new Thread(ty, "A");
            t1.start();
            Thread t2 = new Thread(ty, "B");
            t2.start();
        }
    
    }

    线程合并join

    class ThreadJoin1 extends Thread{
        @Override
        public void run() {
            for (int i = 1; i <=10; i++) {
                //this.sleep(200);
                System.out.println(this.getName()+":"+i);
            }
        }
    }
    
    class ThreadJoin2 extends Thread{
    
        @Override
        public void run() {
            try {
                for (int i = 1; i <=10; i++) {
                    System.out.println(this.getName()+":"+i);
                    if(i==3){ //TheadJoin1执行完
                        ThreadJoin1 tt = new ThreadJoin1();
                        tt.setName("one");
    //                    tt.join();//加入
                        tt.start();
                        tt.join();//加入
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public class str {
        public static void main(String[] args) {
            ThreadJoin2 t = new ThreadJoin2();
            t.setName("two");
            t.start();
        }
    }

    这里需要注意:join需要放在start后面

    线程同步:

    买票的例子:

    有10张票,有2个售票窗口同时卖票,要求不能一个窗口一次都卖完,所有的票总和最终是10张;

    共享数据,没有被所有线程共享

    public class Ticket extends Thread {
         int num = 10;// 票数10张
        @Override
        public void run() {
            while (num > 0) {
                num--;// 买了一张
                System.out.println(this.getName() + ",卖了第:" + (10 - num) + ",还剩:" + num + "张票!");
    
            }
            System.out.println("售罄!!!");
        }
    
    }
    
    public static void main(String[] args) {
            Ticket t1 = new Ticket();
            t1.setName("窗口1");
            t1.start();
            Ticket t2 = new Ticket();
            t2.setName("窗口2");
            t2.start();
    
        }
    
    窗口1,卖了第:1,还剩:9张票!
    窗口2,卖了第:1,还剩:9张票!
    窗口1,卖了第:2,还剩:8张票!
    窗口2,卖了第:2,还剩:8张票!
    窗口1,卖了第:3,还剩:7张票!
    窗口2,卖了第:3,还剩:7张票!
    窗口2,卖了第:4,还剩:6张票!
    窗口2,卖了第:5,还剩:5张票!
    窗口2,卖了第:6,还剩:4张票!
    窗口2,卖了第:7,还剩:3张票!
    窗口1,卖了第:4,还剩:6张票!
    窗口1,卖了第:5,还剩:5张票!
    窗口1,卖了第:6,还剩:4张票!
    窗口1,卖了第:7,还剩:3张票!
    窗口1,卖了第:8,还剩:2张票!
    窗口1,卖了第:9,还剩:1张票!
    窗口1,卖了第:10,还剩:0张票!
    售罄!!!
    窗口2,卖了第:8,还剩:2张票!
    窗口2,卖了第:9,还剩:1张票!
    窗口2,卖了第:10,还剩:0张票!
    售罄!!!
    
    一共买了20张票

    把共享资源,写成静态成员,实现数据的共享

    public class Ticket extends Thread {
         static int num = 10;// 票数10张,共享资源同步
    
        @Override
        public void run() {
            while (num > 0) {
                num--;// 买了一张
                System.out.println(this.getName() + ",卖了第:" + (10 - num) + ",还剩:" + num + "张票!");
    
            }
            System.out.println("售罄!!!");
        }
    
    }
    
    public static void main(String[] args) {
            Ticket t1 = new Ticket();
            t1.setName("窗口1");
            t1.start();
            Ticket t2 = new Ticket();
            t2.setName("窗口2");
            t2.start();
    
        }
    
    窗口1,卖了第:1,还剩:9张票!
    窗口2,卖了第:1,还剩:9张票!
    窗口1,卖了第:2,还剩:8张票!
    窗口2,卖了第:3,还剩:7张票!
    窗口1,卖了第:4,还剩:6张票!
    窗口2,卖了第:4,还剩:6张票!
    窗口2,卖了第:6,还剩:4张票!
    窗口1,卖了第:6,还剩:4张票!
    窗口2,卖了第:7,还剩:3张票!
    窗口1,卖了第:7,还剩:3张票!
    窗口2,卖了第:8,还剩:2张票!
    窗口1,卖了第:8,还剩:2张票!
    窗口1,卖了第:9,还剩:1张票!
    窗口2,卖了第:9,还剩:1张票!
    窗口2,卖了第:10,还剩:-1张票!
    售罄!!!
    窗口1,卖了第:11,还剩:-1张票!
    售罄!!!
    虽然共享数据已经是共享的,但结果还是乱的;

    共享数据同步操作

    如果想解决这样的问题,就必须使用同步,所谓的同步就是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。

    同步代码块和同步方法两种方式完成。

    同步代码块

    在代码块上加上“synchronized”关键字的话,则此代码块就称为同步代码块。 
    同步代码块格式:
    synchronized(同步对象){
            需要同步的代码 ;
        }
    只有唯一的对象才能作为对象锁使用!!!
    对象锁 this  new Object  new Tikcet()   Class类型 Person.class  Student.class  Animal.class
    
    this代表的是当前类对象,继承Thread类,开启线程会实例化多次,每个线程对象都有自己的this;所以不能用this作为对象锁!!!
    
    
    
    窗口1,卖了第:1,还剩:9张票!
    窗口1,卖了第:2,还剩:8张票!
    窗口1,卖了第:3,还剩:7张票!
    窗口2,卖了第:4,还剩:6张票!
    窗口2,卖了第:5,还剩:5张票!
    窗口2,卖了第:6,还剩:4张票!
    窗口2,卖了第:7,还剩:3张票!
    窗口2,卖了第:8,还剩:2张票!
    窗口2,卖了第:9,还剩:1张票!
    窗口2,卖了第:10,还剩:0张票!
    售罄!!!
    售罄!!!

    同步方法

    这里需要注意,在继承Thread的方法实现的线程的时候,这个方式是不好使的,因为他是用的对象锁是this

    同步方法使用的对象锁是:this
    //同步方法
        public synchronized int mySale() throws InterruptedException{
            int i=0;
            if (num > 0) {
                sleep(500);// 卖一张票所需时间
                num--;
                System.out.println(this.getName() + ",卖了第:" + (10 - num) + ",还剩:" + num + "张票!");
            } else {
                System.out.println("售罄!!!");
             //    break;
                i=1;
            }
            return i;
        }

    完整的同步

    public class Ticket extends Thread {
        static int num = 10;// 票数10张,共享资源同步
        private static Object obj = new Object(); // 静态的对象锁 全局变量
    
        @Override
        public void run() {
            try {
                while (true) {
                    // synchronized (obj) {//(参数) 对象锁 this new Object new Tikcet()
                    synchronized (Ticket.class) {// Class 类型作为对象锁
                        if (num > 0) {
                            sleep(500);// 卖一张票所需时间
                            num--;
                            System.out.println(this.getName() + ",卖了第:" + (10 - num) + ",还剩:" + num + "张票!");
                        } else {
                            System.out.println("售罄!!!");
                            break;
                        }
                    }
                    // 调用同步方法
                    /*
                     * int i = this.mySale(); if(i==1){ break; }
                     */
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        // 同步方法
        public synchronized int mySale() throws InterruptedException {
            int i = 0;
            if (num > 0) {
                sleep(500);// 卖一张票所需时间
                num--;
                System.out.println(this.getName() + ",卖了第:" + (10 - num) + ",还剩:" + num + "张票!");
            } else {
                System.out.println("售罄!!!");
                // break;
                i = 1;
            }
            return i;
        }
    
    }

    通过实现Runnable来进行线程的同步

    这里因为Runnale只需要实例化一次,所以用this没有影响。推荐使用线程同步的时候使用Runnable方法

    public class Ticket1 implements Runnable {
        int num = 10;// 票数10张,共享资源同步
        Object obj = new Object(); // 静态的对象锁 全局变量
    
        @Override
        public void run() {
            try {
                while (true) {
                    // synchronized (obj) {//(参数) 对象锁 this new Object new Tikcet()
                    // synchronized (Ticket1.class) {// Class 类型作为对象锁
                    /*
                     * synchronized (this) {// Class 类型作为对象锁 if (num > 0) {
                     * Thread.currentThread().sleep(500);// 卖一张票所需时间 num--;
                     * System.out.println(Thread.currentThread().getName() + ",卖了第:"
                     * + (10 - num) + ",还剩:" + num + "张票!"); } else {
                     * System.out.println("售罄!!!"); break; } }
                     */
                    // 调用同步方法
    
                    int i = this.mySale();
                    if (i == 1) {
                        break;
                    }
    
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        // 同步方法
        public synchronized int mySale() throws InterruptedException {
            int i = 0;
            if (num > 0) {
                Thread.currentThread().sleep(500);// 卖一张票所需时间
                num--;
                System.out.println(Thread.currentThread().getName() + ",卖了第:" + (10 - num) + ",还剩:" + num + "张票!");
            } else {
                System.out.println("售罄!!!");
                // break;
                i = 1;
            }
            return i;
        }
    
    }

    线程同步时通过继承Thread和实现Runnable接口,对象锁区别

    继承Thread

    共享资源,必须是静态的才能被共享;

    能用的对象锁:Class类型,静态对象

    实现Runnable接口

    共享资源,普通成员;

    能用的对象锁:Class类型,静态对象,普通对象,this ,同步方法

    只要做线程同步,推荐使用实现Runnable接口

    方法定义的完整格式

    访问权限{public|default|protected|private} [final] [static] [synchronized] 返回值类型|void 方法名称(参数类型 参数名称,…..) [throws Exception1,Exception2]{

                  [return [返回值|返回调用处]] ; }

    生产者消费者问题

    wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

    wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。

    notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

    wait()  notify() notifyAll() 是Object类中的方法!!!
    共享资源为:库房 
    生成电视10台,卖电视10台,当库存为0时,生成电视线程开启,销售电视线程等待;
    当生成电视,库存为4时,生成电视线程等待;
    
    
    // 仓库
    public class Store {
        int num=0;//库存
        
        //生成电视
        public synchronized void product(int i) throws InterruptedException{//i 生成了第几台电视
               if(num==4){//库存满,等待
                   this.wait();
               }
                //生成一台电视耗时
                Thread.currentThread().sleep(300);
                num++;//生产了一台电视
                System.out.println(Thread.currentThread().getName()+",生成了第:"+i+"台电视,库存为:"+num);
                this.notify();//唤醒消费线程,消费(销售电视)
            
        }
        //销售电视
        public synchronized void sale(int i) throws InterruptedException{
            if(num==0){
                this.wait();
            }
            //销售一台电视耗时
            Thread.currentThread().sleep(100);
            num--;//销售了一台电视
            System.out.println(Thread.currentThread().getName()+",销售了第:"+i+"台电视,库存为:"+num);
            this.notify();//唤醒生产线程,生产电视
        }
    }
    
    public class Product implements Runnable{
        private Store s;
        
        public Product() {
        }
        public Product(Store s) {
            this.s = s;
        }
    
    
        @Override
        public void run() {
            try {
                for (int i = 1; i <=10; i++) {
                    s.product(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
        }
    
    }
    
    public class Sale implements Runnable {
        private Store s;
    
        public Sale() {
        }
    
        public Sale(Store s) {
            this.s = s;
        }
    
        @Override
        public void run() {
            try {
                for (int i = 1; i <=10; i++) {
                    s.sale(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    
    
    public class Test {
        public static void main(String[] args) {
            //库房
            Store s = new Store();
            //生产者
            Runnable pro=new Product(s);
            Thread tp=new Thread(pro, "生产者");
            tp.start();
            //消费者
            Runnable sal=new Sale(s);
            Thread ts = new Thread(sal,"消费者");
            ts.start();
        }
    
    }
    生产者,消费者案例

    线程的生命周期

  • 相关阅读:
    系统吞吐量(TPS)、用户并发量、性能测试概念和公式
    javascript 匿名函数和闭包
    构建高可扩Web架构和分布式系统实战
    Javascript prototype 的作用
    myeclipse下载地址
    tomacat7.0配置(windows)
    IEEE802.11
    C#(多态)
    C#(泛型集合的使用)
    C#(对象引用)
  • 原文地址:https://www.cnblogs.com/taozizainali/p/10858159.html
Copyright © 2011-2022 走看看