Java多线程

多线程的缘起:进程的创建开销太大,进程内部程序还可以再并发,需要在此基础上进一步划分以提高并发。

1、多线程基础

  ①Thread多线程的实现:继承Thread类后改写run方法。

复制代码
class Student extends Thread{
    String name;
    Student(String name){
        this.name = name;
    }
    public void run(){
        for(int i = 0; i < 5; i++)
            System.out.println(String.format("%-10s%d", name, i));
    }
}

public class test {
    public static void main(String[] args) throws Exception {
        new Student("hi").start();
        new Student("hey").start();
        new Student("hello").start();
    }
}
Student extend Thread
复制代码

  问题:为什么不是new MyThread().run()执行?    

    •   因为多线程程序执行涉及到cpu资源分配,这是一个系统调用函数;
    •   不同操作系统的系统调用不同,需要JVM的额外处理。所以需要再start函数中做一些额外处理,而不能把run当成普通函数直接调用执行。

②Runnable方式:MyThread继承Runnable接口实现run方法,以MyThread初始化Thread类new Thread(MyThread)。使用接口可以避免单继承的局限,且方便数据共享

复制代码
class MyTicket implements Runnable{
    private int ticket = 10;
    public void run(){
        for (int i = 0; i < 20; i++) {
            if(ticket > 0)
                System.out.println("买票 =" + this.ticket--);
        }
    }
}
public class test {
    public static void main(String[] args) {
        MyTicket mt = new MyTicket();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    }
}
MyTicket implements Runnable
复制代码

常用方法:

  Thread.sleep(1000);     ms

  Thread.yield();       临时暂停,为使其它线程抢占cpu资源

  p.start();p.join();     join表示等p运行完后main主线程才开始运行

  Thread.currentThread().getName();    当前线程名称

  setPriority(Thread.MAX_PRIORITY);     MIN_PRIORITY  1,NORM_PRIORITY 5,MAX_PRIORITY 10

2、线程同步-临界资源互斥访问 

  概念:应对多线程同时修改一个数据时可能出现的问题。

  注意:run函数中访问的全局变量是final类型,输出10001或9999等。

  问题:9999,当前10000+1add运算还未结束时,sub运算来了 在10000上减一,于是数值由10000 -> 10001 -> 9999。

复制代码
class Student{
    int number;
    Student(int number){
        this.number = number;
    }
    public void sub(){
        this.number --;
    }
    public void add(){
        this.number ++;
    }
}

public class test {
    public static void main(String[] args) throws Exception {
        final Student s = new Student(10000);
        int n = 9000;

        Thread[] addThreads = new Thread[n];
        Thread[] subThreads = new Thread[n];

        for (int i = 0; i < n; i++) {
            Thread t = new Thread( ()->{s.sub();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } );
            t.start();
            addThreads[i] = t;
        }
        for (int i = 0; i < n; i++) {
            Thread t = new Thread( ()->{s.add();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } );
            t.start();
            subThreads[i] = t;
        }

        for(Thread t : addThreads)
            t.join();
        for(Thread t : subThreads)
            t.join();
        System.out.printf("Student's number is %d!\n" , s.number);
    }
}
new Thread( ()->{} )
复制代码

   解决①:synchronized(object){...object...} 表示当前进程独占改对象,其它进程访问时则等待。

复制代码
1)Thread t = new Thread( ()->{ synchronized (s){  s.sub(); } } );
2)public void add(){
        synchronized (this) {
            this.number++;
        }
    }
3)public
synchronized void add(){
    ...
}

复制代码

  解决②:Lock lock = new ReentrantLock();  lock.lock();  lock.unlock();

      Lock和synchronized都是一直请求占用对象,lock.tryLock(1, TimeUnit.SECONDS)只坚持请求1秒。

  比较Lock        synchronized

    接口        关键字

    有tryLock()方法   循环等待占有

    手动释放锁     同步结束和异常时自动释放锁 

复制代码
class Student{
    int number;
    Student(int number){
        this.number = number;
    }
    public void sub(){
        this.number --;
        System.out.println("sub, this number is :\t" + this.number);
    }
    public void add(){
        this.number ++;
        System.out.println("add, this.number is :\t" + this.number);
    }
}

public class test {
    public static void main(String[] args) throws Exception {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        final Student s = new Student(1);
        int n = 6;

        Thread[] addThreads = new Thread[n];
        Thread[] subThreads = new Thread[n];

        for (int i = 0; i < n; i++) {
            Thread t = new Thread( ()->{
                lock.lock();
                    try {
                        if(s.number <= 1)
                            condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    s.sub();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                lock.unlock();
                }  );
            t.start();
            addThreads[i] = t;
        }
        for (int i = 0; i < n; i++) {
            Thread t = new Thread( ()->{
                lock.lock();
                    s.add();
                    if(s.number > 1)
                        condition.signal();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                lock.unlock();
                }  );
            t.start();
            subThreads[i] = t;
        }

        for(Thread t : addThreads)
            t.join();
        for(Thread t : subThreads)
            t.join();
        // System.out.printf("Student's number is %d!\n" , s.number);
    }
}
示例lock-unlock
复制代码

  解决③:原子访问/原子操作 是不可中断的操作,如i++由3个原子操作组成 不是线程安全的。

AtomicInteger atomicI =new AtomicInteger(10);
int i = atomicI.decrementAndGet();     // 9
int j = atomicI.incrementAndGet();     // 10
int k = atomicI.addAndGet(3);          // 13
复制代码
public class test {
    static int value1 = 0;
    static AtomicInteger value2 =new AtomicInteger(0);
    public static void main(String[] args) throws Exception {
        int n = 100000;
        Thread[] ts1 = new Thread[n], ts2 = new Thread[n];
        for(int i = 0; i < n; i++){
            Thread t = new Thread(
                    ()->{
                        value1++;
                    }
            );
            t.start();
            ts1[i] = t;
        }
        for(int i = 0; i < n; i++)
            ts1[i].join();

        for(int i = 0; i < n; i++){
            Thread t = new Thread(
                    ()->{
                        value2.incrementAndGet();
                    }
            );
            t.start();
            ts2[i] = t;
        }
        for(int i = 0; i < n; i++)
            ts2[i].join();

        System.out.printf("after increase %d, the value1 and value2 are :%d\t%d", n, value1, value2.intValue());
    }
}
示例i++原子操作
复制代码

3、线程安全类(所有方法都用synchronized修饰)

    HashTable        HashMap

    线程安全         线程不安全(但速度快很多)

    不允许null的k-v     允许k或v为null

    hash=key.hashCode()   (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

扩容: 原容量2倍 + 1      原容量2倍(于hash计算方式有关)

hash冲突:链表          链表长度大于8时转红黑树

    StringBuffer      StringBuilder

    Vector         ArrayList

非安全转安全集合:借助Collections.synchronizedList、-Map、-SetArrayList、HashMap、HashSet、LinkedList安全化。

List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = Collections.synchronizedList(list1);

死锁:不可剥夺、请求保持、循环等待、互斥访问

复制代码
class Student{
    String name;
    Student(String name) {
        this.name = name;
    }
}

public class test {
    public static void main(String[] args) throws Exception {
        final Student s1 = new Student("hi"), s2 = new Student("hello");

        new Thread( ()->{
            synchronized (s1){
                System.out.println("A\t已经占有s1");
                
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println("A\t正在等待占有s2...");
                synchronized (s2){System.out.println("A\t已经占有s2");};
            };
        }).start();

        new Thread( ()->{
            synchronized (s2){
                System.out.println("B\t已经占有s2");
                
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println("B\t正在等待占有s1...");
                synchronized (s1){System.out.println("B\t已经占有s1");};
            };
        }).start();

    }
}
演示制造造死锁
复制代码

4、线程交互

synchronized + this.wait() + this.notify() 和 Lock、await()、signal()

  this.wait()    让占有该this的线程等待 并释放synchronized的临时占有。

  this.notify()   通知那些等待在this的线程 可以苏醒了。。。this.notify()只通知一个,notifyAll()通知所有。

复制代码
class Student{
    int number;
    Student(int number){
        this.number = number;
    }
    public synchronized void sub() throws InterruptedException {
        if(this.number <= 1)
            this.wait();
        this.number --;
        System.out.println("sub: the number is  " + this.number);
    }
    public synchronized void add(){
        this.number ++;
        this.notify();
        System.out.println("add: the number is  " + this.number);
    }
}


public class test {
    public static void main(String[] args) throws Exception {
        final Student s = new Student(2);
        int n = 5;

        Thread[] addThreads = new Thread[n];
        Thread[] subThreads = new Thread[n];

        for (int i = 0; i < n; i++) {
            Thread t = new Thread( ()->{
                synchronized (s){
                    try {
                        s.sub();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } } );
            t.start();
            addThreads[i] = t;
        }
        for (int i = 0; i < n; i++) {
            Thread t = new Thread( ()->{
                synchronized (s){s.add();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } } );
            t.start();
            subThreads[i] = t;
        }

        for(Thread t : addThreads)
            t.join();
        for(Thread t : subThreads)
            t.join();
        
    }
}
示例集中表现于Student类上 
复制代码

 

posted @   shines87  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示