Java多线程 --Thread

简介: Java多线程 --Thread

         

多线程

概念:多线程是指从软硬件上实现多条执行流程的技术



多线程的创建

方式一:继承Tread类


Java是通过java.lang.Thread类来代表线程的。


实现步骤:


创建继承Thread类


重写run类


创建线程对象


调用start()方法启动


优缺点:


优点:编码简单


缺点:存在单继承的局限性,线程类继承Thread后,不能继承其他类,(单一继承),不便于扩展。不能返回结果

/*
目标:多线程的创建方式一
1. 创建继承Thread类
2. 重写run类
3. 创建线程对象
4. 调用start()方法启动
每次执行的子主线程顺序不一样
但是主线程的主要执行的 必须要在start启动之后
不然就是一个单线程  不能实现多线程的功能
*/
public class ThreadDemo01 {
    public static void main(String[] args) {
        //3.new一个新线程
        Thread ts = new MyThread();
        //4。调用start方法、启动线程
        ts.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程执行" + i);
        }
    }
}
/*
 * 1.创建MyThread类继承Thread类
 * */
class MyThread extends Thread {
     //2.重写run()方法   里面是定义线程
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程执行" + i);
        }
    }
}


方式二:实现Runnable接口


第一种方式步骤

  1. 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
  2. 创建MyRunnable任务对象
  3. 把MyRunnable任务对象交给Thread处理。
  4. 调用线程对象的start()方法启动线程


优缺点

  1. 优点:线程任务类只是实现了Runnale接口,可以继续继承和实现。
  2. 缺点:如果线程有执行结果是不能直接返回的。
public class ThreadDemo02 {
    public static void main(String[] args) {
        //3.创建MyRunnable对象
        Runnable target = new MyRunnable();//多态写法
        //4.把MyRunnable任务对象交给Thread处理。
        Thread t = new Thread(target);
        //5.start()方法启动线程
        t.start();
        //主线程任务
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程执行!!" + i);
        }
    }
}
//1.定义MyRunnable实现 Runnable接口
class MyRunnable implements Runnable {
    //2.重写run()方法
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程执行输出" + i);
        }
    }
}


第二种方式步骤:

  • 实现Runnable接口(匿名内部类形式
  • 可以创建Runnable的匿名内部类对象。
  • 交给Thread处理。
  • 调用线程对象的start()启动线程。
/*
- 实现Runnable接口(匿名内部类形式)
- 可以创建Runnable的匿名内部类对象。
- 交给Thread处理。
- 调用线程对象的start()启动线程。
*/
public class ThreadDemo02Other {
    public static void main(String[] args) {
        //第一个子线程
        //创建MyRunnable对象
        Runnable target = new Runnable(){
            //2.重写run()方法
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程1执行输出" + i);
                }
            }
        };
        //把MyRunnable任务对象交给Thread处理。
        Thread t = new Thread(target);
        //start()方法启动线程
        t.start();
        //第二个子线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程2执行输出" + i);
                }
            }
        }).start();
        //第三个子线程
        new Thread(()-> {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程3执行输出" + i);
                }
        }).start();
        //主线程任务
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程执行输出" + i);
        }
    }
}

方式三:JDK5.0新增 实现Callable接口

优点是:能得到返回结果

利用Callable、FutureTask接实现。得到任务对象


定义类实现Callable接口,重写call方法,封装要做的事情。


用FutureTask把callable对象封装成线程任务对象。


把线程任务对象交给Thread处理。


调用Thread的start方法启动线程,执行任务


线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。优缺点

  • 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
  • 可以在线程执行完毕后去获取线程执行的结果。
  • 缺点;代码复杂
public class ThreadDemo03 {
    public static void main(String[] args) {
        //第一个线程
        //3.创建Callable任务对象
        Callable<String> call = new MyCallable(100);
        //4、把Callable任务对象交给FutureTask对象
        //FutureTask对象的作用1:是Runnable的对象(实现了Runnable接口),可以交给Thread
        //FutureTask对象的作用2:可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果
        FutureTask<String> f1 = new FutureTask<>(call);
        //5.交给线程处理
        Thread t1 = new Thread(f1);
        //6.启动线程
        t1.start();
        //第二个线程
        Callable<String> call1 = new MyCallable(10);
        FutureTask<String> f2 = new FutureTask<>(call1);
        Thread t2 = new Thread(f2);
        t2.start();
        //7.get方法获取任务执行的结果
        try {
            //如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。
            String s1 = f1.get();
            System.out.println("线程1获取到的结果"+s1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            //如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。
            String s2 = f2.get();
            System.out.println("线程1获取到的结果"+s2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//1.定义一个类 实现Callable接口  应该声明 线程任务执行完毕后的结果的数据类型
class MyCallable implements Callable<String> {
    //定义一个变量
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }
    //2.重写call方法
    @Override
    public String call() throws Exception {
        //求和
        int sum = 0;
        for (int i = 0; i <= n; i++) {
            sum += i;
        }
        return "子线程执行的结果是:" + sum;
    }
}


Thread类的常用方法


方法 说明
getName() 获取线程名称
setName() 设置名称
currentThread() 获取当前线程对象
构造器 说明
public Thread(String name) 可以为当前线程指定名称 (一般不用设置)
public Thread(Runnable target) 可以为当前线程指定名称
public Thread(ThreadGroup group, Runnable target) 封装Runnable对象成为线程对象,并指定线程名称
public static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)结束后继续执行



public class ThreadApiDemo04 {
    public static void main(String[] args) {
        //创建Thread对象
        Thread t1 = new MyThread("1号线程");
        //启动线程
        t1.start();
        //设置线程的名称
//        t1.setName("1号线程");
        //当前线程的名称
        System.out.println("t1线程的名称:" + t1.getName());
        Thread t2 = new MyThread("2号线程");
        t2.start();
//        t2.setName("2号线程");
        System.out.println("t2线程名称:" + t2.getName());
        //哪个线程执行它 就得到哪个线程的名称(当前线程对象)
        //主线程名称就是main
        Thread n = Thread.currentThread();
        System.out.println(n.getName());
        //修改主线程名字
        n.setName("最牛的线程。");
        for (int i = 0; i < 5; i++) {
            System.out.println(n.getName() + "输出" + i);
        }
    }
}
class MyThread extends Thread {
    public MyThread() {
    }
    public MyThread(String name) {
        //为当前对象设置名称 送给父类的有参构造方法构造器初始化名称
        //就不用setName的设置名称
        super(name);
    }
    //重写run()
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);//哪个线程执行它 就得到哪个线程的名称(当前线程对象)
        }
    }
}

Thread线程的休眠方法public static void sleep(long millis)

  for (int i = 0; i < 5; i++) {
            System.out.println(n.getName() + "输出" + i);
            if (i == 3){
                //让线程休息一会
                //交钱就走快一点
                Thread.sleep(3000);//3s
            }
        }


线程安全

多个线程同时操作同一个共享资源的时候可能会出现业务安全问题

出现原因


  • 存在多线程并发
  • 同时访问共享资源
  • 存在修改共享资源

案例解释

/*
* 取钱业务
*   需求:
         小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元,模拟2人同时去取钱10万。
    分析:
        ①:需要提供一个账户类,创建一个账户对象代表2个人的共享账户。
        ②:需要定义一个线程类,线程类可以处理账户对象。
        ③:创建2个线程对象,传入同一个账户对象。
        ④:启动2个线程,去同一个账户对象中取钱10万。
* */
//主线程
public class ThreadSafetyTest {
    public static void main(String[] args) {
        //1.定义一个线程类 创建一个共享的账户对象
        Account acc = new Account("ICBC-1", 100000);
        //2.创建2个线程对象,代表小明和小红
        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();
    }
}
//账户类
public class Account {
    private String cardId;//卡号
    private double money;//账户余额
    public Account() {
    }
    //有参构造器
    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }
    //  小明和 小红取钱
    public void drawMoney(double money) {
        //1.先判断谁来取钱  线程名字的人名
        String name = Thread.currentThread().getName();
        //2.判断账户余额是否够钱
        if (this.money >= money) {
            //先取钱再更新余额
            //3.取钱
            System.out.println(name + "来取钱成功 吐出" + money);
            //4.更新余额
            this.money -= money;
            //提示
            System.out.println(name + "来取钱后剩余:" + this.money);
        } else {
            System.out.println(name+"来取钱,但是余额不足!!");
        }
    }
    public String getCardId() {
        return cardId;
    }
    public void setCardId(String cardId) {
        this.cardId = cardId;
    }
    public double getMoney() {
        return money;
    }
    public void setMoney(double money) {
        this.money = money;
    }
}
/*
* 取钱的线程类  要继承Thread
* */
public class DrawThread extends Thread {
    //接受处理账户的对象
    private Account acc;
    public DrawThread(Account acc,String name) {
        super(name);//必须要在最前面
        this.acc = acc;
    }
    //重写方法
    @Override
    public void run() {
        //小明  小红  取钱
        acc.drawMoney(100000);
    }
}


线程同步(解决线程安全问题)

加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。唯一锁

让多个线程实现先后依次访问共享资源



加锁方式


方式一:同步代码块


作用:把出现线程安全问题的核心代码给上锁。


原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。


对出现问题的核心代码使用synchronized进行加锁


每次只能一个线程占锁进入访问


要求:锁对象只要对于当前同时执行的线程来说是同一个对象即可。 不能用任意唯一的锁作为锁

synchronized(同步锁对象){
  核心共享资源的代码(核心代码)
}
上面存在安全问题的代码
    //同步代码块
        //锁名称要唯一
        synchronized ("kcs") {
            //2.判断账户余额是否够钱  (以下存在安全问题)
            if (this.money >= money) {
                //先取钱再更新余额
                //3.取钱
                System.out.println(name + "来取钱成功 吐出" + money);
                //4.更新余额
                this.money -= money;
                //提示
                System.out.println(name + "来取钱后剩余:" + this.money);
            } else {
                System.out.println(name+"来取钱,但是余额不足!!");
            }
        }

锁对象的规范要求



建议使用共享资源作为锁对象


对于实例方法建议使用this作为锁对象。


对于静态方法建议使用字节码(类名.class)对象作为锁对象。


方式二:同步方法


作用:把出现线程安全问题的核心方法给上锁。


原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

public synchronized void drawMoney(double money) 

同步方法底层原理


同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。


如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象!


如果方法是静态方法:同步方法默认用类名.class作为的锁对象。


方式三:Lock锁


Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象。


方法 说明
lock 获得锁
unLock 解锁


try - catch - finally

// final修饰后:锁对象是唯一和不可替换的,非常专业
private final Lock lock = new ReentrantLock();
public  void drawMoney(double money) {
        //1.先判断谁来取钱  线程名字的人名
        String name = Thread.currentThread().getName();
        Lock.Lock();//上锁
            //2.判断账户余额是否够钱  (以下存在安全问题)
      try{
                if (this.money >= money) {
                    //先取钱再更新余额
                    //3.取钱
                    System.out.println(name + "来取钱成功 吐出" + money);
                    //4.更新余额
                    this.money -= money;
                    //提示
                    System.out.println(name + "来取钱后剩余:" + this.money);
                } else {
                    System.out.println(name+"来取钱,但是余额不足!!");
                }finally{
                   lock.unLock();解锁 
                }
        }    
    }


线程通信

概念:所谓线程通信就是线程间相互发送数据,线程间共享一个资源即可实现线程通信。

常见形式


  1. 通过共享一个数据的方式实现。
  2. 根据共享数据的情况决定自己该怎么做,以及通知其他线程怎么做

应用场景


  1. 生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费生产者产生的数据。
  2. 要求:生产者线程生产完数据后唤醒消费者,然后等待自己,消费者消费完该数据后唤醒生产者,然后等待自己。

常用方法

void wait() 让当前线程等待并释放所占锁,直到另一个线程调用notify()方法或 notifyAll()方法
void notify() 唤醒正在等待的单个线程
void notifyAll() 唤醒正在等待的所有线程



注意:上述方法应该使用当前同步锁对象进行调用。

线程池(重点)

复用线程的技术



问题

不使用线程池的问题:如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。

线程池实现的API、参数说明

线程池接口:ExecutorService



创建线程池对象:

方式一:实现类 ThreadPoolExecutor自创建一个线程池对象 (重点)

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)


参数一:指定线程池的线程数量(核心线程): corePoolSize 不能小于0

参数二:指定线程池可支持的最大线程数: maximumPoolSize 最大数量>=核心线程数量

参数三:指定临时线程的最大存活时间: keepAliveTime 不能小于0

参数四:指定存活时间的单位(秒、分、时、天): unit 时间单位

参数五:指定任务队列:workQueue 不能为null

参数六:指定用哪个线程工厂创建线程: threadFactory 不能为null

参数七:指定线程忙,任务满的时候,新任务来了怎么办: handler 不能为null


临时线程什么时候创建

  • 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。


什么时候会开始拒绝任务

  • 核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝。

方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象



线程池处理Runnable任务

  • void execute(Runnable command)
/*
 * 自定义一个线程池 ,并测试其特性
 * */
public class ThreadPoolDemo01 {
    public static void main(String[] args) {
        /*
        * public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
                              * */
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        //2.给任务线程池处理[
        MyRunnables mr = new MyRunnables();
        pool.execute(mr);
        pool.execute(mr);
        pool.execute(mr);
        //线程复用 已经超出了线程池的大小
        pool.execute(mr);
        pool.execute(mr);
        //停止线程  开发中一般不使用
        pool.shutdownNow();//立即关闭 即使任务没有完成
        pool.shutdown();//任务跑完才关闭  因为在sleep不能关闭
    }
}
class MyRunnables implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "输出了==》" + i);
        }
        //睡眠
        try {
            System.out.println(Thread.currentThread().getName() + "本线程已绑定,线程任务进入休眠状态~~~");
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}



线程池处理Callable任务

Future<T> submit(callable<T> task) 执行callable任务,返回未来任务对象获取线程结果

public class ThreadPoolDemo02 {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        //给任务线程池处理
        Future<String> s1 = pool.submit(new MyCallable(50));
        Future<String> s2 = pool.submit(new MyCallable(150));
        Future<String> s3 = pool.submit(new MyCallable(250));
        Future<String> s4 = pool.submit(new MyCallable(350));
        Future<String> s5 = pool.submit(new MyCallable(450));
//        String s = s1.get();
//        System.out.println(s);
        System.out.println(s1.get());
        System.out.println(s2.get());
        System.out.println(s3.get());
        System.out.println(s4.get());
        System.out.println(s5.get());
    }
}
class MyCallable implements Callable<String> {
    //定义一个变量
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }
    @Override
    public String call() throws Exception {
        //求和
        int sum = 0;
        for (int i = 0; i <= n; i++) {
            sum += i;
        }
        return Thread.currentThread().getName()+"执行1-"+n+"的和的结果是:"+ sum;
    }
}


Executors工具类实现线程池

方法名称 说明
public static ExecutorService newCachedThreadPoo1() 线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉。
public static ExecutorService newFixedThreadPool(int nThreads) 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
public static ExecutorService newSingleThreadExecutor () 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。
public static scheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。


Executors的底层其实也是基于线程池的实现类ThreadPoolExecutor创建线程池对象的。


Executors不适合做大型互联网场景的线程池方案


建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则规避资源耗尽的风险。

/*
* Executors工具方法直接得到一个线程池对象
* */
public class ExecutorsDemo01 {
    public static void main(String[] args) {
        //创建固定线程池对象
        ExecutorService pools = Executors.newFixedThreadPool(3);
        pools.execute(new MyRunnables());
        pools.execute(new MyRunnables());
        pools.execute(new MyRunnables());
        //超出线程  没有多余线程
        pools.execute(new MyRunnables());
        pools.execute(new MyRunnables());
    }
}
public class MyRunnables {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "输出了==》" + i);
        }
        //睡眠
        try {
            System.out.println(Thread.currentThread().getName() + "本线程已绑定,线程任务进入休眠状态~~~");
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

定时器(Timer)

  • schedule(TimerTask task, long delay, long period) 在指定 的延迟之后开始 ,重新执行 固定延迟执行的指定任务
/*
*
* 目标: 定时器的使用和了解
* */
public class TimerDemo01 {
    public static void main(String[] args) {
        //1.创建Timer定时器
        Timer t = new Timer();  //单线程
        //2.调用定时器 处理任务  匿名内部类
        t.schedule(new TimerTask() { 
            @Override
            public void run() {
                System.out.println("执行一次~~");
            }
        },3000,2000);   //delay 是3秒后才启动  period是每两秒执行一次
    }
}


ScheduledExecutorService的优点

  1. 基于线程池,某个任务的执行情况不会影响其他定时任务的执行。
/*
 * 基于线程池,某个任务的执行情况不会影响其他定时任务的执行。
 * */
public class TimerDemo02 {
    public static void main(String[] args) {
        //1.创建ScheduledExecutorService线程池 做定时器
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3); //定时线程池的大小
        //2.开启定时任务
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出AAA==>" + new Date());
                //A任务进行睡眠
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 0, 1, TimeUnit.SECONDS);// TimeUnit unit 是 时间的单位
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出BBB==>" + new Date());
                System.out.println(10 / 0);//存在异常
            }
        }, 0, 1, TimeUnit.SECONDS);// TimeUnit unit 是 时间的单位
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出CCC==>" + new Date());
            }
        }, 0, 1, TimeUnit.SECONDS);// TimeUnit unit 是 时间的单位  间隔两秒
    }
}



线程状态等

正在运行的程序(软件)就是一个独立的进程,线程是属于进程的,多个线程其实是并发与并行同时进行的。



  • 线程的状态:也就是线程从生到死的过程,以及中间经历的各种状态及状态转换。
  • 理解线程的状态有利于提升并发编程的理解能力。

Java线程的状态


  1. Java总共定义了6种状态
  2. 6种状态都定义在Thread类的内部枚举类中。
public enum State {
     NEW,  //新建        线程刚被创建,但是并未启动。
    RUNNABLE,//可运行      线程已经调用了start()等待CPU调度
    BLOCKED, //锁阻塞      线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态;。
    WAITING,//无线等待       一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒  
    TIMED_WAITING,//计时等待  同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。带有超时参数的常用方法有Thread.sleep、Object.wait。
    TERMINATED;//被终止    因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。
}


并法、并行


  1. CPU同时处理线程的数量有限。
  2. CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发。
  • 并发:CPU分时轮询的执行线程。
  • 并行:同一个时刻同时在执行。
目录
相关文章
|
8天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
7天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
7天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
6天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
12天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
37 9
|
9天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
12天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
14天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
4月前
|
Java 开发者
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
58 0
|
30天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
34 1
下一篇
无影云桌面