JAVA多线程总结(一)

一、线程创建和互斥

创建多个线程,对银行账户执行存款和取款操作

1、继承Runnable接口,创建线程类MyBank

public class MyBank implements Runnable {
    private final Bank bank;
    private final Long withdrawMoney;
    private final Long depositMoney;

    public MyBank(Bank b,Long m1,Long m2){
        this.bank=b;
        this.withdrawMoney=m1;
        this.depositMoney=m2;
    }

    public void run(){
        System.out.println("thread is running.");
        while(true){
            savingMoney(bank,depositMoney);
            withdrawMoney(bank,withdrawMoney);
        }
    }
    public void savingMoney(Bank bank,Long m){
        bank.deposit(m);
        System.out.println(bank.getAccount()+" deposit "+m+" ¥, current balance="+bank.getMoney());
    }
    public void withdrawMoney(Bank bank,Long m){
        if(bank.withdraw(m)){
            System.out.println(bank.getAccount()+" withdraw "+m+" ¥, current balance="+bank.getMoney());
        }else{
            System.out.println(bank.getAccount()+" withdraw failed,not enough money. current balance="+bank.getMoney());
        }
    }
}


2、创建银行类Bank, 使用synchronized关键字实现线程互斥

public class Bank {
    private Long money;
    private String account;
    public Bank(String account,Long money){
        this.money=money;
        this.account=account;
    }
    public synchronized void deposit(Long save){
        money+=save;
    }
    public synchronized boolean withdraw(Long m){
        if(money>=m){
            money-=m;
            return true;
        }else{
            return false;
        }
    }
    public String getAccount(){
        return account;
    }
    public Long getMoney(){
        return money;
    }
}

3、在Main类中创建多个线程,多银行实现多线程读写

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class Main {

    public static void main(String[] args) {
        //通过Thread创建线程
//        PrintThread thread1=new PrintThread("thread 1 running");
//        PrintThread thread2=new PrintThread("thread 2 running");
//        thread1.start();
//        thread2.start();

        //线程暂停
      /*  for(int i=0;i<10;i++){
            System.out.println("Good");
            try{
                Thread.sleep((1000));
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }*/

      //使用ThreadFactory创建线程
        ThreadFactory factory= Executors.defaultThreadFactory();
        Bank mybank=new Bank("ALEXon",1000L);
        MyBank t1=new MyBank(mybank,10L,5L);
        MyBank t2=new MyBank(mybank,5L,10L);
        factory.newThread(t1).start();
        factory.newThread(t2).start();
        }

    }
}

二、Single Thread Execution模式

该模式下,同一时间内只能允许一个线程执行处理,就像独木桥同一时间只允许一个人通行

SharedResource共享资源

SharedResource指可被多个线程访问的类,包含的方法分为两类:safeMethod和unsafeMethod

  • safeMethod:多个线程同时调用也不会发生问题的方法
  • unsafeMethod:多个线程同时调用会发生问题的方法,必须加以保护的方法;

临界区

只允许单个线程执行的程序范围称为临界区。

死锁

死锁是指两个线程分别持有着锁,相互等待着对方释放锁的现象;发生死锁的线程都无法继续执行,程序失去了生存性。

发生死锁的条件:

  • 存在多个SharedResource角色
  • 线程在持有着某个SharedResource角色的锁同时,还想获取其他SharedResource角色的锁
  • 获取SharedResource角色的锁的顺序不固定(SharedResource角色是对称的)

原子操作

不可分割的操作

synchronized互斥关键字

  • synchronized可以保证共享资源同一时间只能被一个线程使用;

  • 但是使用了synchronized的方法性能会比没有使用的差,因为要处理线程冲突,挂锁和解锁过程;

  • synchronized方法和synchronized代码块无论是执行return还是抛出异常,都一定能够释放锁。

synchronized实例

三个人不断的通过一个Gate门

Gate类

public class Gate {
    private int counter=0;
    private String name="nobaody";
    private String address="Nowhere";
    //synchronized关键字确保同一时间只有一个线程执行该方法
    public synchronized void pass(String name,String address){
        this.counter++;
        this.name=name;
        this.address=address;
        check();
    }
    //synchronized关键字确保同一时间只有一个线程执行该方法
    public synchronized String toString(){
        return "No."+counter+": "+name+", "+address;
    }
    private void check(){
        if(name.charAt(0)!=address.charAt(0)){
            System.out.println("-------------Broken------------:"+toString());
        }
    }
}

UserThread类:

public class UserThread extends Thread{
    private final Gate gate;
    private final String myname;
    private final String myaddress;
    public UserThread(Gate gate,String myname,String address){
        this.gate=gate;
        this.myname=myname;
        this.myaddress=address;
    }

    public void run(){
        System.out.println(myname+" BEGIN.....");
        while(true){
            gate.pass(myname,myaddress);
        }
    }
}

Main类:

public class Main {
        /*Single Thread Execution模式*/
        System.out.println("Test Gate, hit CTRL+C to exit.");
        Gate gate= new Gate();
        new UserThread(gate,"Alex","Aubei").start();
        new UserThread(gate,"Bob","Biangxi").start();
        new UserThread(gate,"Jackson","Jeijing").start();
    }
}

计数信号量

假设能够使用的资源个数是N个,而需要这些资源的线程个数大于N,就会导致资源竞争,这是需要使用计数信号量Semaphore类。

Semaphore中的acquire方法用于确保存在可用的资源,当存在可用资源时,线程会立即从acquire方法中返回,同时信号量内部的资源个数减1;如果没有可用资源时,线程则阻塞在acquire方法内,直至出现可用资源;

Semaphore中的release方法用于释放资源,释放后,信号量内部的资源个数加1;

acquire和release必须成对使用;

计数信号量实例

1、Log类

public class Log {
    public static void println(String s){
        System.out.println(Thread.currentThread().getName()+": "+s);
    }
}

2、有限的资源类

import java.util.Random;
import java.util.concurrent.Semaphore;
/**
 * 有限的资源类
 */
public class BoundedResource {
    private final Semaphore semaphore;
    private final int permits;//允许的资源个数
    private final static Random random=new Random(314159);

    public BoundedResource(int permits){
        this.permits=permits;
        this.semaphore=new Semaphore(permits);
    }

    public void use() throws InterruptedException{
        // 获取资源
        semaphore.acquire();
        try{
            // 获取资源后执行操作
            doUse();
        }catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            // 释放资源
            semaphore.release();
        }
    }

    protected void doUse() throws InterruptedException{
        Log.println("BEGIN:   used="+(permits-semaphore.availablePermits()));
        Thread.sleep(random.nextInt(500));
        Log.println("END   used="+(permits-semaphore.availablePermits()));
    }
}

3、线程创建类

import java.util.Random;

public class SemaphoreUserThread extends Thread {
    private final static Random random=new Random(265353);
    private final BoundedResource resource;

    public SemaphoreUserThread(BoundedResource resource){
        this.resource=resource;
    }

    public void run(){
        try{
            while(true){
                resource.use();
                Thread.sleep(random.nextInt(3000));
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

4、Main类

public class Main {

    public static void main(String[] args) {
        /*Semaphore计数信号量*/
        // 创建资源,只允许4个线程使用
        BoundedResource resource=new BoundedResource(4);
        // 创建10个线程
        for(int i=0;i<10;i++){
            new SemaphoreUserThread(resource).start();
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值