• Java多线程操作


    Java中的线程

    一个程序的运行须要启动一个应用进程,一个进程能够创建多个线程。帮助应用完毕多任务操作。实现并发运行。在Java中线程是被封装成Thread类。进行多线程操作时仅仅须要继承一个Thread类,实现自己的功能就可以。然后开启此线程,或者你也能够实现一个Runnable接口。然后将其传递给Thread对象。然后再启动它。

    线程的创建于启动

    继承Thread

    创建一个类并继承Thread类,然后实现Thread类的run方法,在run方法内填上自己的代码。然后创建这个自己定义类,并调用其start方法来启动这个自己定义线程。

    // 引入Thread
    import java.lang.Thread;
    
    /**
     * 创建自己的Thread,实现run方法(放上自己要运行的内容)
     */
    class MyThread extends Thread {
    
        /**
         * 覆盖超类Thread的run方法
         */
        public void run() {
            for(int i=0; i<10; i++) {
                System.out.println("第" + i + "次循环");
            }
        }
    }
    class ThreadDemo1 {
        public static void main(String[] args) {
            // 创建一个自己定义线程。而且启动它
            new MyThread().start();
        }
    }
    /* 程序输出:
    第0次循环
    第1次循环
    第2次循环
    第3次循环
    第4次循环
    第5次循环
    第6次循环
    第7次循环
    第8次循环
    第9次循环
    */

    实现Runnable

    一个实现过Runnable的对象都能够被一个Thread对象所运行。

    import java.lang.Thread;
    import java.lang.Runnable;
    /**
     * 创建一个类,实现Runnable接口。

    */ class MyRunnable implements Runnable { /** * 实现Runnable的run方法 */ public void run() { for(int i=0; i<5; i++) { System.out.println("Runable:第" + i + "次循环"); } } } class ThreadDemo2 { public static void main(String[] args) { // 创建一个线程。并创建一个实现过Runnable的对象 // 构造它,然后再启动这个线程 new Thread(new MyRunnable()).start(); } } /* 程序输出: Runable:第0次循环 Runable:第1次循环 Runable:第2次循环 Runable:第3次循环 Runable:第4次循环 */

    synchronized的使用

    既然是多线程。那么就会出现多线程的问题。如同一时候訪问同一资源。从而产生意料之外的结果。这是我们所不想看到的。在Java中能够非常easy的解决问题。使用synchronized对操作进行加锁。synchronized能够对对象加锁,也能够对函数进行加锁。以下对照一下未使用synchronized和使用synchronized的不同之处。

    未使用synchronized的情况

    import java.lang.Thread;
    import java.lang.Runnable;
    
    class MyRunnable implements Runnable {
        private static int i=0;
        public void run() {
            for(; i<10; i++) {
                try {
                    Thread.sleep(10);   
                } catch(Exception e) {
    
                }
                print(i);
            }
        }
    
        private void print(int k) {
            System.out.println(k);
        }
    }
    
    class Demo {
        public static void main(String[] args) {
            MyRunnable r = new MyRunnable();
            new Thread(r).start();
            new Thread(r).start();
        }
    }

    能够看到结果不对,由于两个线程可能会同一时候进入线程,然后打印出两个同样的值。

    0
    0
    2
    3
    4
    5
    6
    7
    8
    9
    10

    使用了synchronized后的情况

    import java.lang.Thread;
    import java.lang.Runnable;
    
    class MyRunnable implements Runnable {
        private static int i=0;
        public void run() {
            synchronized(this) {
                for(; i<10; i++) {
                    try {
                        Thread.sleep(10);   
                    } catch(Exception e) {
    
                    }
                    print(i);
                }
            }
        }
    
        private void print(int k) {
            System.out.println(k);
        }
    }
    
    class Demo {
        public static void main(String[] args) {
            MyRunnable r = new MyRunnable();
            new Thread(r).start();
            new Thread(r).start();
        }
    }

    当对for进行加锁处理后,便不会同一时候两个线程进入循环,这样打印的数字便不会出错。

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

    synchronized的加锁对象会有一个标志位(0/1)。默认的情况下是0,当线程运行到synchronized的加锁对象后假设对象的标志位为0。那么将其设置为1,否则等待。

    这个标志位能够称之为“锁旗标”。这样以来便能够实现线程同步。
    尽管synchronized攻克了多线程的不安全问题。可是也是有一定的弊端的。它会减少程序的运行效率,所以。synchronized不能够任意放置,应尽量将其放到必须使用的位置上。

    如单例模式的一个样例:

    public class Single {
    
        private Single mInstance;
    
        private Single(){
    
        }
    
        public static Single getInstance() {
            if(mInstance == null) {
                synchronized(Single.class) {
                    if(mInstance == null) {
                        mInstance = new Single();
                    }
                }
            }
            return mInstance;
        }
    }

    这里的synchronized能够加在getInstance()前面,可是这样会大大减少运行效率,也能够去掉外层的if(mInstance == null),可是这样也会添加不必要的推断,以为假设mInstance已经创建后便不须要锁了。若此以来,上面这样的写法是最好的。

    最内层的if推断有必要说明一下,能够假设这样一种情况,两个线程都运行到第一个if的后面,那么。假设没有内层的if推断的话,mInstance会被创建两次,所以,内层的if是不可或缺的。

    waitnotify的使用

    waitnotify是Object对象中的两个方法。其作用是用于多线程中的控制,如想使用两个线程交替打印出OddEven时,详细代码例如以下:

    import java.lang.Thread;
    import java.lang.Runnable;
    
    class Temp {
        public static boolean flag = false;
    }
    
    class Odd implements Runnable{
    
        public void run() {
            while(true) {
                if(Temp.flag) {
                    try {
                        wait();
                    } catch(Exception e) {}
                }
                System.out.println("Odd");
                Temp.flag = !Temp.flag;
                try {
                    notify();
                } catch(Exception e) {}
            }
        }
    }
    
    class Even implements Runnable {
    
        public void run() {
            while(true) {
                if(!Temp.flag) {
                    try {
                        wait();
                    } catch(Exception e) {}
                }
                System.out.println("Even");
                Temp.flag = !Temp.flag;
                try {
                    notify();
                } catch(Exception e) {}
            }
        }
    }
    
    class Demo {
        public static void main(String[] args) {
            new Thread(new Odd()).start();
            new Thread(new Even()).start();
        }
    }

    当然除了notify方法,还有notifyAll方法。用于唤醒全部线程。

    Lock的使用

    JDK1.5之后。也就是Java5.0之后。添加了很多新的内容,如用于线程控制的一些类,Lock的用法相当于synchronizedLocklock()unlock()分别用于加锁和解锁,一般用法例如以下:

    import java.lang.Runnable;
    import java.lang.Thread;
    import java.util.concurrent.locks.*;
    
    class Locks implements Runnable {
        private Lock lock = new ReentrantLock();
        private int index = 0;
        public void run() {
            while(true) {
                lock.lock();
                System.out.print(index + " ");
                try {
                    Thread.sleep(100);
                } catch(Exception e) {}
                index ++;
                lock.unlock();
            }
        }
    }
    
    class Demo {
        public static void main(String[] args) {
            Locks locks = new Locks();
            new Thread(locks).start();
            new Thread(locks).start();
            new Thread(locks).start();
        }
    }

    这样便能够顺序打印出0 1 2 3 4 ···
    通过Lock的对象,我们能够创建Condition对象,如
    Condition condition = lock.newCondition();
    然后能够使用condition.await();condition.signal()来暂停和唤醒线程,当然还有condition.signalAll()来唤醒全部线程。

  • 相关阅读:
    unix操作系统一些笔记
    安装SQL SERVER2008 R2出现的几个问题
    js中的类型和函数参数传递类型问题
    js一些要点
    百度2015年前端笔试题(南京区域)
    js 函数中的 this 问题
    html细节
    前后台读取Web.config中的值的方法
    使用的 SQL Server 版本不支持数据类型“datetime2”.
    物料主数据MRP4中的独立/集中
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7197529.html
Copyright © 2020-2023  润新知