java多线程实操

线程原子性问题

 package com.smalltiger.juc;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * Created by smalltiger on 2018/5/9.
     * 一、i++的原子性问题:i++的操作实际上分为三个步骤“读-改-写”
     *      int i=10;
     *      i=i++;//10
     *
     *      int temp=i;
     *      i=i+1;
     *      i=temp;
     *  二、原子变量:java.util.concurrent.atomic 包下提供了常用的原子变量:
     *      1.volatile修饰 :保证内存可见性
     *      2.CAS(Compare-And-Swap)算法保证了数据的原子性
     *          CAS算法是硬件对于并发操作共享数据的支持
     *          CAS包含了三个操作数:
     *          内存值V
     *          预估值A
     *          更新值B
     *          当且仅当V==A时,V==B,否则,将不做任何操作
     */
    public class TestAtomicDemo {
        public static void main(String[] args) {
            AtomicDemo ad=new AtomicDemo();
    
            for (int i = 0; i < 10; i++) {
                new Thread(ad).start();
            }
        }
    }
    class AtomicDemo implements Runnable{
    
        //private int serialNumber=0;
        private AtomicInteger serialNumber = new AtomicInteger();
    
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+getSerialNumber());
        }
    
        public int getSerialNumber() {
            return serialNumber.getAndIncrement();
        }
    }

Callable创建线程

package com.smalltiger.juc;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * Created by smalltiger on 2018/5/9.
 * 一:创建执行线程的方式三:实现Callable接口。相较于实现Runnable接口的方式,方法可以有返回值,并可以抛出异常。
 */
public class TestCallable {
    public static void main(String[] args) {
        ThreadDemo1 td = new ThreadDemo1();

        //1.执行Callable方式,需要FutureTask实现类的支持,用于接受运算结果。
        FutureTask<Integer> result = new FutureTask<Integer>(td);

        new Thread(result).start();

        //2.接受线程后运算结果
        try {
            Integer sum = result.get();
            System.out.println(sum);
            System.out.println("---------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
class ThreadDemo1 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum=0;

        for (int i = 0; i < 100000; i++) {
            System.out.println(i);
            sum+=i;
        }
        return sum;
    }
}

模拟CAS算法

/**
 * Created by smalltiger on 2018/5/9.
 * 模拟CAS算法
 */
public class TestCompareAndSwap {

    public static void main(String[] args) {
       final CompareAndSwap cas=new CompareAndSwap();
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    int expectedValue=cas.get();
                    boolean b=cas.compareAndSet(expectedValue,(int)(Math.random()*101));
                    System.out.println(b);
                }
            }).start();
        }
    }
}
class CompareAndSwap{
    private int value;

    //获取内存值
    public synchronized int get(){
        return value;
    }

    //比较
    public synchronized int compareAndSwap(int expectedValue,int newValue){
        int oldValue=value;

        if (oldValue==expectedValue){
            this.value=newValue;
        }

        return oldValue;
    }

    //设置
    public synchronized boolean compareAndSet(int expectedValue,int newValue){
        return expectedValue==compareAndSwap(expectedValue,newValue);
    }
}

volatile 关键字

package com.smalltiger.juc;

/**
 * Created by smalltiger on 2018/5/9.
 * 一:volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据是可见的。
 *                      相较于synchronized是一种轻量级的同步策略
 *     注意:
 *     1.volatile不具备“互斥性”
 *     2.volatile不能保证变量的"原子性"
 */
public class TestVolatile {
    public static void main(String[] args) {
        ThreadDemo td=new ThreadDemo();
        new Thread(td).start();

        while (true){
                if (td.isFlag()){
                    System.out.println("-----------");
                    break;
                }
        }
    }
}
class ThreadDemo implements Runnable{
    private volatile boolean flag=false;
    @Override
    public void run() {

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag=true;

        System.out.println("flag="+isFlag());
    }

    public boolean isFlag(){
        return flag;
    }

    public void setFlag(boolean flag){
        this.flag=flag;
    }
}

java多线程之读写锁

package com.smalltiger.juc;

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by smalltiger on 2018/5/10.
 *1.ReadWriteLock : 读写锁
 *
 * 写写/读写 需要"互斥"
 * 读读 不需要互斥
 *
 */
public class TestReadWriteLock {
    public static void main(String[] args) {
        ReadWriteLockDemo rw=new ReadWriteLockDemo();

        new Thread(new Runnable() {
            @Override
            public void run() {
                rw.set((int)(Math.random()*101));
            }
        },"Write").start();

        for (int i = 0; i <100 ; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    rw.get();
                }
            }).start();
        }
    }
}
class ReadWriteLockDemo{
    private int number=0;
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    //读
    public void get(){
        lock.readLock().lock(); //上锁
        try {
            System.out.println(Thread.currentThread().getName()+":"+number);
        }finally {
            lock.readLock().unlock();   //释放锁
        }
    }
    //写
    public void set(int number){
        lock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName());
            this.number=number;
        }finally {
            lock.writeLock().unlock();
        }
    }
}

线程之共享变量-生产者,消费者代码之一(使用lock锁)

package com.smalltiger.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by smalltiger on 2018/5/9.
 */
public class TestProductorAndConsumerForLock {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer cus = new Consumer(clerk);

        new Thread(pro,"生产者 A").start();
        new Thread(cus,"消费者 B").start();

       new Thread(pro,"生产者 C").start();
       new Thread(cus,"消费者 D").start();
    }
}
//店员
class Clerk{
    private int product=0;

    private Lock lock = new ReentrantLock();    //创建同步锁
    private Condition condition = lock.newCondition();  //创建同步锁的通信
    //进货
    public void get(){
        lock.lock();
        try {
            while (product>=1){     //为了避免虚假唤醒问题,应该总是使用在循环中
                System.out.println("产品已满!");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                }
            }
            System.out.println(Thread.currentThread().getName()+":"+ ++product);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
    //卖货
    public void sale(){
        lock.lock();
        try {
            while (product<=0){
                System.out.println("缺货!");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                }
            }
            System.out.println(Thread.currentThread().getName()+":"+ --product);
            condition.signalAll();
        } finally {
        lock.unlock();
        }
    }
}
//生产者
class Productor implements Runnable{
    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {

            }

            clerk.get();
        }
    }
}
//消费者
class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}

线程之共享变量-生产者,消费者代码之二

package com.smalltiger.juc;

/**
 * Created by smalltiger on 2018/5/9.
 */
public class TestProductorAndConsumer {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer cus = new Consumer(clerk);

        new Thread(pro,"生产者 A").start();
        new Thread(cus,"消费者 B").start();

        new Thread(pro,"生产者 C").start();
        new Thread(cus,"消费者 D").start();
    }
}
/*//店员
class Clerk{
    private int product=0;
    //进货
    public synchronized void get(){
        while (product>=1){     //为了避免虚假唤醒问题,应该总是使用在循环中
            System.out.println("产品已满!");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        System.out.println(Thread.currentThread().getName()+":"+ ++product);
        this.notifyAll();
    }
    //卖货
    public synchronized void sale(){
        while (product<=0){
            System.out.println("缺货!");
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        System.out.println(Thread.currentThread().getName()+":"+ --product);
        this.notifyAll();
    }
}
//生产者
class Productor implements Runnable{
    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {

            }

            clerk.get();
        }
    }
}
//消费者
class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}*/

自定义ForkJoin方法

package com.smalltiger.juc;

import org.junit.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

/**
 * Created by smalltiger on 2018/5/10.
 */
public class TestForkJoinPool {
    //自定义ForkJoin方法
    public static void main(String[] args) {
        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();

        ForkJoinTask<Long> task = new ForkJoinSumCalculate(0L,100000000000L);//7045->14308

        Long sum = pool.invoke(task);

        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为: "+ Duration.between(start,end).toMillis());
    }
    //普通单线程for循环
    @Test
    public void test1(){
        Instant start = Instant.now();
        long sum = 0L;

        for (long i = 0L; i <=100000000000L; i++) {  //13155->26236
            sum+=i;
        }
        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为: "+ Duration.between(start,end).toMillis());
    }
    //java8新特性
    @Test
    public void test2(){
        Instant start = Instant.now();

        Long sum = LongStream.rangeClosed(0L,100000000000L)//3842->7830
                            .parallel()
                             .reduce(0L,Long::sum);
        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为: "+ Duration.between(start,end).toMillis());
    }
}
class ForkJoinSumCalculate extends RecursiveTask<Long>{

private long start;
private long end;

private static final long THURSHOLD=10000L;//临界值

    public ForkJoinSumCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
       long length = end-start;

       if (length<=THURSHOLD){
           long sum=0L;
           for (long i = start; i <=end; i++) {
               sum+=i;
           }
           return sum;
       }else{
           long middle = (start+end)/2;

           ForkJoinSumCalculate left = new ForkJoinSumCalculate(start,middle);
           left.fork();//进行拆分,同时压入线程队列

           ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle+1,end);
           right.fork();

           return left.join()+right.join();
       }
    }
}

CountDownLatch:闭锁

package com.smalltiger.juc;

import java.util.concurrent.CountDownLatch;

/**
 * Created by smalltiger on 2018/5/9.
 * CountDownLatch:闭锁,在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才继续执行
 */
public class TestCountDownLatch {
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(50);
        LatchDemo ld=new LatchDemo(latch);

        long start=System.currentTimeMillis();

        for (int i = 0; i <50 ; i++) {
            new Thread(ld).start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {

        }
        long end=System.currentTimeMillis();

        System.out.println("耗费时间为:"+(end-start));
    }
}
class LatchDemo implements Runnable{
    private CountDownLatch latch;

    public LatchDemo(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        synchronized (this) {
            try {
                for (int i = 0; i < 50000; i++) {
                   if (i%2==0){
                       System.out.println(i);
                   }
                }
            } finally {
                latch.countDown();
            }
        }
    }
}

线程经典题目: 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。 *如:ABCABCABC…… 依次递归

package com.smalltiger.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by smalltiger on 2018/5/9.
 * 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。
 *如:ABCABCABC…… 依次递归
 */

    public class TestABCAlternate {
        public static void main(String[] args) {
            AlternateDemo ad = new AlternateDemo();
    
            new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <=20; i++) {
                                ad.loopA(i);
                            }
                        }
                    },"A"
            ).start();
    
            new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <=20; i++) {
                                ad.loopB(i);
                            }
                        }
                    },"B"
            ).start();
    
            new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <=20; i++) {
                                ad.loopC(i);
    
                                System.out.println("-----------");
                            }
                        }
                    },"C"
            ).start();
        }
    }
    class AlternateDemo{
        private int number =1;//当前正在执行线程的标记
    
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
    
        /*
        *@param totalLoop:循环第几轮
         */
        public void loopA(int totalLoop){
            lock.lock();
            try {
                //1.判断
                if (number!=1){
                    condition1.await();
                }
                //2.打印
                for (int i = 1; i <=1; i++) {
                    System.out.println(Thread.currentThread().getName()+"\t"+i+"\t"+totalLoop);
                }
                //3.唤醒
                number=2;
                condition2.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
        }
    
        public void loopB(int totalLoop){
            lock.lock();
            try {
                //1.判断
                if (number!=2){
                    condition2.await();
                }
                //2.打印
                for (int i = 1; i <=1; i++) {
                    System.out.println(Thread.currentThread().getName()+"\t"+i+"\t"+totalLoop);
                }
                //3.唤醒
                number=3;
                condition3.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
        }
    
        public void loopC(int totalLoop){
            lock.lock();
            try {
                //1.判断
                if (number!=3){
                    condition3.await();
                }
                //2.打印
                for (int i = 1; i <=1; i++) {
                    System.out.println(Thread.currentThread().getName()+"\t"+i+"\t"+totalLoop);
                }
                //3.唤醒
                number=1;
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
        }
    }

猜你喜欢

转载自blog.csdn.net/smsmtiger/article/details/84633437