专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java基础之并发编程(java并发编程实战怎么样)

temp10 2024-10-13 09:29:30 java教程 11 ℃ 0 评论

  前言

  程序:一组有序的指令集合

  进程:执行中的程序

Java基础之并发编程(java并发编程实战怎么样)

  线程:是进程中“单一持续控制流程”

  进程跟程序的区别:程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般说来,一个进程肯定与一个程序相对应,并且只有 一个,但是一个程序可以有多个进程,或者一个进程都没有。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候会产生进程。

  进程与线程的区别:进程作为资源分配的单位,线程是调度和执行的单位

  线程状态

  新生状态、就绪状态、阻塞状态、运行状态、死亡状态

  多线程的实现

  Thread

  PS:无法实现线程之间的数据共享

    /**
     * 通过 extends Thread
     */
    public class MyThread extends Thread{

        private final String name;

        public MyThread(String name){
            this.name = name;
        }

        @Override
        public void run(){
            for (int i = 0; i < 5; i++) {
                System.out.println(this.name + ":" + i);
            }
        }
    }
    public static void main(String[] args) {
        MyThread myThread = new MyThread("MyThread-0");
        myThread.start();
    }

  Runnable

    /**
     * 通过 implements Runnable
     */
    public class MyRunnable implements Runnable{

        private final String name;

        public MyRunnable(String name){
            this.name = name;
        }

        @Override
        public void run(){
            for (int i = 0; i < 5; i++) {
                System.out.println(this.name + ":" + i);
            }
        }
    }
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable("MyRunnable-0");
        new Thread(myRunnable).start();

    }

  Callable<V>

    /**
     * 通过 implements Callable<V>
     */
    public class MyCallable implements Callable<String> {

        private final String name;

        public MyCallable(String name){
            this.name = name;
        }

        @Override
        public String call() throws Exception {
            for (int i = 0; i < 5; i++) {
                System.out.println(this.name + ":" + i);
            }
            return "执行完成";
        }
    }
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable("MyCallable-0");
        new Thread(new FutureTask<String>(myCallable)).start();

    }

  线程池

    public static void main(String[] args) {
        MyThread myThread = new MyThread("MyThread-0");
        MyRunnable myRunnable = new MyRunnable("MyRunnable-0");
        MyCallable myCallable = new MyCallable("MyCallable-0");

        //线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        threadPool.submit(myThread);
        threadPool.submit(myRunnable);
        threadPool.submit(myCallable);

        //关闭线程池
        threadPool.shutdown();
    }

  并发安全

  synchronized

  使用synchronized关键字对线程加锁,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步、互斥操作。

  同步代码块

synchronized(Obj){//obj叫做同步监听器,只能是引用类型

}

  同步方法

public synchronized void fun(){//同步方法中,默认使用this当前对象作为同步对象 

}

  Lock

  从jdk1.5之后,java提供了另外一种方式来实现同步访问,那就是Lock。

//可重入锁
Lock lock = new ReentrantLock();

//加锁
lock.lock();

try{
    //并发处理逻辑...
}catch(Exception ex){
     
}finally{
    //释放锁
    lock.unlock();
}

  老公、老婆同时取钱例子:

/**
 * 银行账户
 */
public class Account {

    //余额
    private int balance = 1000;

    public Account() {
    }

    public Account(int balance) {
        this.balance = balance;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

}

  使用synchronized

/**
 * 通过 implements Runnable
 */
public class MyRunnable implements Runnable{

    private final String name;

    private final Account account;

    public MyRunnable(Account account,String name){
        this.account = account;
        this.name = name;
    }

    @Override
    public void run(){
        for (int i = 0; i < 5; i++) {
            //加锁,锁的是银行账户对象
            synchronized (account) {
                //余额大于200
                if (account.getBalance() >= 200) {

                    //模拟耗时
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //取钱成功
                    account.setBalance(account.getBalance() - 200);
                    System.out.println(this.name + "取走了200元,当前余额为:" + account.getBalance());
                } else {
                    System.out.println(this.name + "取钱失败,余额不足");
                }
            }
        }
    }
}

  使用Lock

/**
 * 通过 implements Runnable
 */
public class MyRunnable implements Runnable{

    private final String name;

    private final Account account;

    //可重入锁
    private static final Lock lock = new ReentrantLock();

    public MyRunnable(Account account,String name){
        this.account = account;
        this.name = name;
    }

    @Override
    public void run(){
        for (int i = 0; i < 5; i++) {
            //加锁
            lock.lock();
            
            try{
                //余额大于200
                if (account.getBalance() >= 200) {

                    //模拟耗时
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //取钱成功
                    account.setBalance(account.getBalance() - 200);
                    System.out.println(this.name + "取走了200元,当前余额为:" + account.getBalance());
                } else {
                    System.out.println(this.name + "取钱失败,余额不足");
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                //释放锁
                lock.unlock();
            }
        }
    }
}

  测试

    public static void main(String[] args) {
        //初始化银行账户
        Account account = new Account();

        //老公、老婆同时取钱
        new Thread(new MyRunnable(account,"老公")).start();
        new Thread(new MyRunnable(account,"老婆")).start();
    }

  如果不加锁,就会出现并发安全问题

  死锁

  死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程

  死锁的发生必须具备以下四个必要条件。

  1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

  2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

  3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

  4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

  后记

  Thread.sleep():使线程进入阻塞状态,会释放CPU资源但不会释放对象锁的控制

  Object.wait():当前线程必须拥有此对象监视器。该线程释放对此监视器的所有权(释放synchronize锁)并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

  Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制

版权声明

作者:huanzi-qch

出处:https://www.cnblogs.com/huanzi-qch

若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.

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

欢迎 发表评论:

最近发表
标签列表