JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

多线程技术(同步异步,并发并行)守护线程(java垃圾回收机制)

wys521 2024-11-27 12:14:30 精选教程 17 ℃ 0 评论

多线程技术概述

每个线程都有自己的栈空间,并用一份堆内存

1.同步和异步

同步:排队执行,效率低但是安全.

异步:同时执行,效率高但是数据不安全.

2.并发与并行

并发:指两个或多个时间在同一个时间段内发生.

并行:指两个或多个时间在同一时刻发生(同时发生)

3.执行步骤,有利于理解线程时用来做什么的


public class Test {
    public static void main(String[] args) throws InterruptedException {
        //1.创建一个任务对象
        Xiancheng x1 = new Xiancheng();
        //2.创建一个线程,并为其分配一个任务
        Thread t = new Thread(x1);
        //3.执行这个线程
        t.start();

    }
}

4.多用Runnable


5.线程对象可以打标记

package com.kkb;

public class Demo01_ThreadInterrupt {
    public static void main(String[] args) {

        Thread t = new Thread(new MyThings());
        t.start();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        t.interrupt();//给线程添加标记


    }
}
class MyThings implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {//中断异常-->>如果这个事物正在执行的线程有了中断标记,那么就进入到catch块中
                //System.out.println("虽然我添加了标记来到了这里,但是,你没有让我死亡哈哈哈哈");
                //加上return资源就释放了
                System.out.println("添加了interrupt标记,后面返回return,我结束了");
                return;
            }
        }
    }
}

6.守护线程

线程:分为守护线程和用户线程

用户线程:当一个进程不包含任何的存货线程时,进程结束

守护线程:守护用户的线程,当最后一个用户线程结束时,所有守护线程自动死亡

package com.kkb;

public class Demo01_ThreadInterrupt {
    public static void main(String[] args) {

        Thread t = new Thread(new MyThings());
        t.setDaemon(true);//设置t为守护线程,当这个应用(进程中最后一个用户线程死亡的时候,守护线程自动死亡)
        t.start();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//        t.interrupt();//给线程添加标记


    }
}
class MyThings implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {//中断异常-->>如果这个事物正在执行的线程有了中断标记,那么就进入到catch块中
                //System.out.println("虽然我添加了标记来到了这里,但是,你没有让我死亡哈哈哈哈");
                //加上return资源就释放了
                System.out.println("添加了interrupt标记,后面返回return,我结束了");
                return;
            }
        }
    }
}

7.线程安全问题

概述:

 * 为什么会导致线程不安全:
 * 首先假定一种情况:当事物中余票为1时,三个线程进入来买票
 * 1.A线程:看到conut>0,进入,正在出票的时候,count还没来得及做数据的变更操作
 * 2.B线程:这个时候,B也进来了,因为conut还没有变更
 * .....
 * 这就是多线程,进入产生时间偏的问题-->>这里为了更好的模拟实际中的放票状态,就引入了一个Thread.sleep,使线程进行休眠的操作
package com.kkb;

/**
 * 为什么会导致线程不安全:
 * 首先假定一种情况:当事物中余票为1时,三个线程进入来买票
 * 1.A线程:看到conut>0,进入,正在出票的时候,count还没来得及做数据的变更操作
 * 2.B线程:这个时候,B也进来了,因为conut还没有变更
 * .....
 * 这就是多线程,进入产生时间偏的问题-->>这里为了更好的模拟实际中的放票状态,就引入了一个Thread.sleep,使线程进行休眠的操作
 * 
 */
public class UnSafe {
    public static void main(String[] args) {
        Runnable r = new Ticket();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        Thread t3 = new Thread(r);
        t1.start();
        t2.start();
        t3.start();
    }
    static class Ticket implements Runnable{
        private int conut = 10;

        @Override
        public void run() {
            while (conut > 0){
                System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                conut--;
                System.out.println("余票:"+conut);
            }
        }
    }
}

8.synchronized锁

注意:看同一把锁!!!!

同步代码块和同步方法都是隐式锁

1.同步代码块

package com.kkb;

/**
 *  所谓上锁:就是在一个线程正在执行任务时,其他的对象只能在外面排队,因为这个事物现在的情况对外是不开放的
 *  指定事物中的一个锁对象,在一个线程进入时,这个对象就会被标记上一把锁
 *  要看同一把锁
 */
public class Safe_Synchronized {
    public static void main(String[] args) {
        Runnable r = new Ticket();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        Thread t3 = new Thread(r);
        t1.start();
        t2.start();
        t3.start();
    }
    static class Ticket implements Runnable{
        private int conut = 10;
        private Object o = new Object();
        //注意这里的o为了保证这个事物中存在一个可以上锁的对象
        @Override
        public void run() {
            while (true) {
                synchronized (o) {
                    if (conut > 0) {
                        System.out.println(Thread.currentThread().getName() + "正在准备卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        conut--;
                        System.out.println("余票:" + conut);
                    }else {
                        break;
                    }
                }
            }
        }
    }
}

2.设计为同步方法

 *  注意这里面锁方法的时候,锁的对象就是这个方法饿地址上加锁,一个一个进入此方法
 *  我们打印出来的this就是:com.kkb.Safe_Synchronized_To_method$Ticket@3694916f
 *  这个方法的地址
 只需要在这个方法上加上synchronized进行标志
package com.kkb;

/**
 *  注意这里面锁方法的时候,锁的对象就是这个方法饿地址上加锁,一个一个进入此方法
 *  我们打印出来的this就是:com.kkb.Safe_Synchronized_To_method$Ticket@3694916f
 *  这个方法的地址
 */
public class Safe_Synchronized_To_method {
    public static void main(String[] args) {
        Runnable r = new Ticket();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        Thread t3 = new Thread(r);
        t1.start();
        t2.start();
        t3.start();
    }
    static class Ticket implements Runnable{
        private int conut = 10;
//        private Object o = new Object();
        //不需要这个对象了
        //因为锁方法的时候锁的其实就是this,这个save方法的this
        //注意这里的o为了保证这个事物中存在一个可以上锁的对象
        //com.kkb.Safe_Synchronized_To_method$Ticket@3694916f
        @Override
        public void run() {
            while (true) {
                boolean sale = sale();
                if (!sale){//如果没票了就结束
                    break;
                }

            }
        }
        public synchronized boolean sale(){
            if (conut > 0) {
                System.out.println(Thread.currentThread().getName() + "正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                conut--;
                System.out.println("余票:" + conut);
                System.out.println(this);
            }else {
                return false;
            }

            return true;
        }
    }
}

3.显示锁

Lock l = new ReentrantLock();
package com.kkb;

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

/**
 *
 */
public class Safe_Synchronized_Lock {
    public static void main(String[] args) {
        Runnable r = new Ticket();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        Thread t3 = new Thread(r);
        t1.start();
        t2.start();
        t3.start();
    }
    static class Ticket implements Runnable{
        private int conut = 10;
        //给一把显式锁
        private Lock l = new ReentrantLock();//Lock锁接口的实现类
        @Override
        public void run() {
            while (true) {
                //每次一个线程进入就会加上一个锁,其他线程无法进入
                l.lock();//加锁
                boolean sale = sale();
                l.unlock();//解锁
                if (!sale){//如果没票了就结束
                    break;
                }

            }
        }
        public boolean sale(){
            if (conut > 0) {
                System.out.println(Thread.currentThread().getName() + "正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                conut--;
                System.out.println("余票:" + conut);
            }else {
                return false;
            }

            return true;
        }
    }
}

4.公平锁和不公平锁

就是在声明显式锁的时候加上一个true.

排队一个一个进,不会出现线程争先恐后的,谁抢到就是谁的

Lock l = new ReentrantLock(true);
Thread-0正在准备卖票
余票:9
Thread-1正在准备卖票
余票:8
Thread-2正在准备卖票
余票:7
Thread-0正在准备卖票
余票:6
Thread-1正在准备卖票
余票:5
Thread-2正在准备卖票
余票:4
Thread-0正在准备卖票
余票:3
Thread-1正在准备卖票
余票:2
Thread-2正在准备卖票
余票:1
Thread-0正在准备卖票
余票:0

9.多线程交互问题

线程的wait和线程的唤醒notifyAll

再引入一个变量交替执行

10.线程池

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁的船舰线程和销毁线程需要时间.线程池就是一个可以容纳多个线程的容器,池中的线程可以反复的使用,省区了频繁创建线程对象的操作,节省了大量的时间和资源.

1.创建线程

2.创建任务

3.执行任务

4.关闭线程

1.缓存线程池

2.定长线程池

3.单线程池

4.周期定长线程池



本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表