zoukankan      html  css  js  c++  java
  • 线程的基本了解

    1、线程的实现方式

    线程有两种实现方式,分别为继承Thread、实现Runnable接口。差异性:实现方式避免了类的继承单一性,且对于多个线程同时访问同一个资源时更便捷。

    (1)继承Thread

    class TestThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    
    public class TestThreadMethod {
        public static void main(String[] args) {
            TestThread th1 = new TestThread();
            th1.setName("testThread");
            th1.start();
        }
    }
    View Code

    (2)实现Runnable接口

    class TestRunnable implements Runnable{
        @Override
        public void run() {
            for (int i=1; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
    
    public class TestMain {
        public static void main(String[] args) {
            TestRunnable tr = new TestRunnable();
            Thread th1 = new Thread(tr, "th1");
            Thread th2 = new Thread(tr, "th2");
            th1.start();
            th2.start();
        }
    }
    View Code

    (3)线程的生命周期

    2、线程的常用方法

    start():线程的开启。同一个线程在结束时只能开启一次,否则报错。

    setName():设置当前线程的名称。

    getName():获取当前线程的名称。

    currentThread():获取当前线程的对象。

    priority():线程的级别。静态值有,0/5(默认)/10。值越高,代表争夺CPU的使用权的几率越大,但不是绝对。

    yield():线程让步。当前线程A调用yield()方法时,释放CPU的使用权,重新与其他线程B争夺CPU的使用权。

    join():线程加入。在A线程中,调用B线程的join方法时,A线程的程序等待B线程的程序执行完才能继续执行A线程。

    sleep():线程睡眠。当线程执行该方法时,进入设置的睡眠时间后继续执行程序。

    isAlive():线程是否在活动,返回值为boolean。

    wait():线程等待。必须在同步方法中使用。

    notify()/notifyAll():线程唤醒,与wait()结合使用,用于线程通信。

    注意:(1)线程在同步时,wait()会释放锁,而join()与sleep()方法不会释放锁。

       (2)wait()、notify()、notifyAll()严格来说不算线程中的方法,这三个方法是定义在Object对象中。

    class TestThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    
    public class TestThreadMethod {
        public static void main(String[] args) {
            TestThread th1 = new TestThread();
            th1.setName("testThread");
            th1.setPriority(Thread.MAX_PRIORITY);
            th1.start();
            
            Thread.currentThread().setName("=======mainThread");
            for (int i = 0; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
                if (i % 10 == 0) {
                    Thread.yield();
                }
                if (i == 20) {
                    try {
                        th1.join();
                        System.out.println(th1.isAlive());
                        th1.start();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    View Code

    3、线程的同步

    线程的同步分为两种:同步代码块和同步方法块。

    class TestThread extends Thread {
        static int ticket = 100;
        static Object obj = new Object();
        
        @Override
        public void run() {
            /*1、同步代码块时,只能同步需要的代码块,其余无关代码块不行,会影响同步;
             * 2、同步监视器用this,代表当前对象,此时继承方式,对象是多个,所以无法同步;
             * 此两种情况出现重复输出情况,如下的this情况
             */
            /*synchronized (this) {
                while(true) {
                        try {
                            Thread.currentThread().sleep(100);
                        } catch (InterruptedException e) {
                            // TODaO Auto-generated catch block
                            e.printStackTrace();
                        }
                        if (ticket <= 0) {
                            break;
                        }
                        System.out.println(Thread.currentThread().getName() + "窗口:" +ticket--);
                    }
                }*/
                while(true) {
                    synchronized (obj) {//obj充当锁时必须是静态的,否则多个对象代表的锁是各自的。
                        try {
                            Thread.currentThread().sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (ticket <= 0) {
                            break;
                        }
                        System.out.println(Thread.currentThread().getName() + "窗口:" +ticket--);
                    }
                }
        }
    }
    
    public class TestMain {
        public static void main(String[] args) {
            TestThread th1 = new TestThread();
            TestThread th2 = new TestThread();
            th1.setName("th1");
            th2.setName("th2");
            th1.start();
            th2.start();
        }
    }
    View Code
    class TestThread implements Runnable {
        int ticket = 100;
        @Override
        public void run() {
            while(true) {
                importNum();
            }
        }
        /**
         * 同步方法块时,同步锁为当前对象.所以方法的类必须是同一个对象
         */
        private synchronized void importNum() {
            if (ticket <= 0) {
                return;
            }
            System.out.println(Thread.currentThread().getName() + "窗口:" + ticket--);
        }
    }
    
    public class TestMain {
        public static void main(String[] args) {
            TestThread th = new TestThread();
            Thread th1 = new Thread(th, "th1");
            Thread th2 = new Thread(th, "th2");
            
            th1.start();
            th2.start();
        }
    }
    View Code

    注:同步在Thread与Runnable两种方式的实现中有很大的区别,详见上例。

    拓展示例:

    class SingleTon {
        private SingleTon() {
            
        }
        public static SingleTon instance = null;
        
        public static SingleTon getSingleTon() {
            /**
             *     原程序直接判断,创建实例,返回。在多线程中,存在线程安全问题,会创建多个SingleTon;
             * 开发中为避免这情况发生,采用下面同步的实现方式。
             */
            /**
                if (instance == null) {
                    instance = new SingleTon();
                }
                return instance;
            */
            if (instance == null) {//提高同步效率,后面访问方法的对象,无需再次等待
                synchronized(SingleTon.class) {//采用类本身的对象来充当锁
                    if (instance == null) {
                        instance = new SingleTon();
                    }
                }
            }
            return instance;
        }
    }
    
    public class TestMain {
        public static void main(String[] args) {
            
            SingleTon st1 = SingleTon.getSingleTon();
            SingleTon st2 = SingleTon.getSingleTon();
        }
    }
    View Code

    4、线程的死锁

    死锁:当两个线程同时需要对方手中的锁时,各自都在等对方放弃手中的锁,而使程序无限期的等待下去,称为死锁。

    public class TestMain {
        public static void main(String[] args) {
            
            StringBuffer sb1 = new StringBuffer();
            StringBuffer sb2 = new StringBuffer();
            
            new Thread(){
                public void run() {
                    
                    synchronized(sb1) {
                        sb1.append("A");
                        try {
                            Thread.currentThread().sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized(sb2) {
                            sb2.append("B");
                            System.out.println("sb1:" + sb1.toString());
                            System.out.println("sb2:" + sb2.toString());
                        }
                    }
                    
                };
            }.start();
            
            new Thread(){
                public void run() {
                    synchronized(sb2) {
                        sb2.append("C");
                        try {
                            Thread.currentThread().sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized(sb1) {
                            sb1.append("D");
                            System.out.println("sb1:" + sb1.toString());
                            System.out.println("sb2:" + sb2.toString());
                        }
                    }
                };
            }.start();
        }
    }
    View Code

    上述例子中,第一个线程执行第一个同步块代码后,进行睡眠,握住sb1的锁;此时第二个线程可能已经开启运行,获取sb2的锁,进行同步代码块方法,进行睡眠。之后第一个线程睡眠时间过后要进行第二个同步代码块的执行,这时sb2的锁握在了第二个线程,而第二个线程在醒来后要获取第二块同步方法的锁时,这时的锁在第一个线程中。两个线程同时在等待对方释放手中的锁,导致了死锁的出现。

    5、线程的通信

    /**
     * 生产者 --> 店员(数量最多存放20) --> 消费者
     *
     */
    
    class Clerk {
        int num;
        public synchronized void addProduct() {
            if (num >= 20) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            notifyAll();
            num++;
            
            System.out.println(Thread.currentThread().getName() + ":" + num);
        }
        public synchronized void consume() {
            if (num == 0) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
            notifyAll();
            System.out.println(Thread.currentThread().getName() + ":" + num);
            num--;
        }
    }
    
    class Customer implements Runnable {
        Clerk clerk;
        
        public Customer(Clerk clerk) {
            this.clerk = clerk;
        }
        
        public void run() {
            while(true) {
                try {
                    Thread.currentThread().sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clerk.consume();
            }
        }
    }
    
    class Producer implements Runnable {
        Clerk clerk;
        
        public Producer(Clerk clerk) {
            this.clerk = clerk;
        }
        
        public void run() {
            while(true) {
                try {
                    Thread.currentThread().sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clerk.addProduct();
            }
        }
    }
    
    public class TestMain {
        public static void main(String[] args) {
            Clerk clerk = new Clerk();
            Customer c1 = new Customer(clerk);
            Producer p1 = new Producer(clerk);
            Thread th2 = new Thread(p1, "生产者");
            Thread th1 = new Thread(c1, "消费者");
            th2.start();
            th1.start();
        }
    }
    View Code

     

     

     

  • 相关阅读:
    11-15SQLserver基础--数据库之范式理论
    11-13SQLserver基础--数据库之事务
    11-11SQLserver基础--数据库之触发器
    C#中abstract和virtual区别
    virtual修饰符
    override 修饰符
    访问public
    访问修饰符protected
    访问修饰符private
    访问修饰符internal
  • 原文地址:https://www.cnblogs.com/wjys/p/9508633.html
Copyright © 2011-2022 走看看