美文网首页
Java多线程,线程同步,线程通讯

Java多线程,线程同步,线程通讯

作者: 帝王鲨kingcp | 来源:发表于2019-02-19 10:31 被阅读0次

    线程的方式

    • Thread和Runnable
      相对比较简单就不多做介绍,无非就是Thread是一个类,Runnable是一个接口。
    • ThreadFactory线程工厂
      用来创建线程的线程工厂,主要就是newThread方法
        static void threadFactory() {
            ThreadFactory factory = new ThreadFactory() {
                AtomicInteger count = new AtomicInteger(0);
    
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, "Thread-" + count.incrementAndGet());
                }
            };
    
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " started!");
                }
            };
    
            Thread thread = factory.newThread(runnable);
            thread.start();
            Thread thread1 = factory.newThread(runnable);
            thread1.start();
        }
    
    • Executor和线程池
      这篇文章详情介绍了Executor
      Android线程池实现原理
    • Callable和Future
      这个最大的特点就是带返回值,Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。
      Callable和Future
        static void callable() {
            Callable<String> callable = new Callable<String>() {
                @Override
                public String call() {
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "Done!";
                }
            };
    
            ExecutorService executor = Executors.newCachedThreadPool();
            Future<String> future = executor.submit(callable);
            try {
                String result = future.get();
                System.out.println("result: " + result);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    

    线程同步和安全

    synchronized关键字实现同步

    • synchronized方法
        public synchronized void showA(){
            System.out.println("showA..");
        }
    
    • synchronized代码块
        public void showC(){
            String s="1";
            synchronized (s) {
                System.out.println("showC..");
            }
    
    • synchronized方法和synchronized代码块区别
      两者的区别:Moinitor对象的不同;synchronized代码块可以同步的范围更小更灵活。同步方法的moinitor是类的对象,而synchronized代码块的moinitor就可以也自己来定义,更加方便。

    • synchronized本质
      保证方法内部或代码块内部资源(数据)的互斥访问。即同⼀时间、由同⼀个Monitor 监视的代码,最多只能有⼀个线程在访问
      保证线程之间对监视资源的数据同步。即,任何线程在获取到 Monitor 后的第⼀时间,会先将共享内存中的数据复制到自己的缓存中;任何线程在释放 Monitor 的第⼀时间,会先将缓存中的数据复制到共享内存中。

    volatile关键字 实现字段的原子性和同步性

    • volatile
      保证加了volatile关键字的字段的操作具有原⼦性和同步性,其中原⼦性相当于实现了针对单⼀字段的线程间互斥访问。因此 volatile 可以看做是简化版的 synchronized。
      volatile 只对基本类型 (byte、 char、 short、 int、 long、 float、 double、 boolean) 的赋值操作和对象的引用赋值操作有效。volatile int a = 1; a++;这种情况不能保证原子性,因为a++有两步操作。
    • java.util.concurrent.atomic 包:
      下面有 AtomicInteger AtomicBoolean 等类,作用和 volatile 基本⼀致,使用如下
            ThreadFactory factory = new ThreadFactory() {
                AtomicInteger count = new AtomicInteger(0);
    
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, "Thread-" + count.incrementAndGet());//count++
                }
            };
    
    • Lock / ReentrantReadWriteLock锁
    1. Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性
    2. ReetrantReadWriteLock读写锁的效率明显高于synchronized关键字
    3. ReetrantReadWriteLock读写锁的实现中,读锁使用共享模式;写锁使用独占模式,换句话说,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的
    4. ReetrantReadWriteLock读写锁的实现中,需要注意的,当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁

    一般都会在finally中释放锁,保证在方法提前结束或出现 Exception 的时候,依然能正常释放锁。

    // 读操作
        public static void readFile(Thread thread) {
            lock.readLock().lock();
            boolean readLock = lock.isWriteLocked();
            if (!readLock) {
                System.out.println("当前为读锁!");
            }
            try {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(thread.getName() + ":正在进行读操作……");
                }
                System.out.println(thread.getName() + ":读操作完毕!");
            } finally {
                System.out.println("释放读锁!");
                lock.readLock().unlock();
            }
        }
    
        // 写操作
        public static void writeFile(Thread thread) {
            lock.writeLock().lock();
            boolean writeLock = lock.isWriteLocked();
            if (writeLock) {
                System.out.println("当前为写锁!");
            }
            try {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(thread.getName() + ":正在进行写操作……");
                }
                System.out.println(thread.getName() + ":写操作完毕!");
            } finally {
                System.out.println("释放写锁!");
                lock.writeLock().unlock();
            }
        }
    

    线程间通讯和交互

    • Thread.interrupt():温和式终结:不立即、不强制,相当于设置了一个中断状态。
      interrupted() 和 isInterrupted():检查(和重置)中断状态,interrupted()会重置中断状态为false,isInterrupted()不会重置中断状态。
      InterruptedException:如果在线程等待时中断,直接结束等待过程(因为等待过程什么也不会做,而interrupt() 的目的是让线程做完收尾工作后尽快终结,所以要跳过等待过程)
        public void runTest() {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        if (Thread.interrupted()) {
                            // 收尾工作 Thread.interrupted()线程中断或重置,所以if条件只会进来一次
                            return;
                        }
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // 收尾工作 如果在睡眠中thread.interrupt()就会立即结束,进入InterruptedException,在这里也会重置中断状态
                            return;
                        }
                    }
                }
            };
            thread.start();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread.interrupt();//中断状态
        }
    
    • Object.wait() 和 Object.notify() / notifyAll()
      wait() 和 notify() / notifyAll() 都需要放在同步代码块里
      在未达到目标时 wait(),让出持有的监视moinitor对象,进入等待队列
      用 while 循环检查
      设置完成后 notifyAll(),唤醒等待队列中的线程去执行操作
    public class WaitDemo implements TestDemo {
        private String mName;
    
        private synchronized void initName() {
            mName= "kingcp";
            notifyAll();
        }
    
        private synchronized void printName() {
            while (mName== null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("name: " + mName);
        }
    
        @Override
        public void runTest() {
            final Thread thread1 = new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    printName();
                }
            };
            thread1.start();
            Thread thread2 = new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    initName();
                }
            };
            thread2.start();
        }
    }
    
    • Thread.join():让Thead线程插在目前运行的自己线程前⾯
    • Thread.yield():暂时让出自己的时间片给 同优先级 的线程

    相关文章

      网友评论

          本文标题:Java多线程,线程同步,线程通讯

          本文链接:https://www.haomeiwen.com/subject/bntpeqtx.html