Java多线程基础


多线程

1.基本概念:程序、进程、线程
  • 程序:为完成特定任务,用某种语言编写成的指令集合
  • 进程: 程序的一次执行,或正在运行的程序。如QQ、微信等,时资源分配的单位
  • 线程: 进程可进一步细化为线程,是一个进程内部执行的一次路径,一个进程至少有一个或者多个线程。线程作为调用和执行的单位,每个线程拥有独立的运行栈和程序计数器,多个线程共享进程的方法区和堆的资源。
  • 多线程: 如运行了QQ进程后,可以发送文件,也可以同时下载文件。
  • 并发:一个时间段内,多个任务按照分配时间片依次进行
  • 并行:一个时间段内,多个任务同时进行
2.线程的创建和使用(4种方式)
  • start方法:开启线程,并调用run方法(线程在被调度时执行的操作 )
  • 1.继承Thread类重写run()方法
public static void main(String[] args) {
    //第一种
    FirstThread firstThread = new FirstThread();
   	firstThread.start();
	FirstThread firstThread1 = new FirstThread();
	firstThread1.start();

	//第二种 通过匿名子类
	new Thread(){
    	@Override
    	public void run() {
        	for (int i = 0; i < 100 ; i++) {
            	if(i % 2 == 0){
                	System.out.println(i);
            	}
        	}
    	}
	}.start();

	//第三种
	new FirstThread().start();
}
  • 2.实现Runnable接口重写run()方法
/**
 * 实现Runnable接口
 * 1.创建实现了Runnable接口的类对象
 * 2.创建Thread对象,通过Thread带参构造函数将上方创建的对象传入
 * 3.调用Thread.start()方法启动线程
 */
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

//第二种 没有上面方式好,如果有多个线程,便会存在多个对象,浪费资源
new Thread(new myRunnable()).start();
  • 线程常用方法
public static void main(String[] args) {
    /**
     * 1.start() 开启线程,调用run方法执行相关操作
     * 2.Thread.currentThread.getName() 获取当前线程名
     * 3.setName() 设置当前线程名
     * 4.getName() 获取当前线程名
     * 5.yield() 释放当前cpu执行权
     * 6.join() 在线程A种调用线程b的join方法,线程A进入阻塞状态,直到线程B执行完成后,线程A才结束阻塞状态
     */
    MyThreadApi myThreadApi = new MyThreadApi();

    //1.start()开启线程,并调用run方法执行相关操作
    new Thread(new MyThreadApi()).start();
    myThreadApi.start();

    //2.Thread.currentThread.getName() 获取当前线程名
    //2.1在当前main方法获取线程名
    Thread.currentThread().getName();
    //2.2获取继承了Thread类的类对象线程名
    myThreadApi.currentThread().getName();

    //3.setName 设置线程名称
    //3.1给当前main方法设置线程名
    Thread.currentThread().setName("主线程:");
    //3.2给继承了Thread类的对象设置线程名
    myThreadApi.setName("我是myThreadApi种的线程:");
}
两种实现多线程方式对比
  • 1.开发中优先选择实现Runnable接口方式:
  • A.没有单继承局限性
  • B.更适合来处理多个线程共享数据的情况
3线程的生命周期
4线程的同步(同步代码块,同步方法,Lock锁 [ lock(),unlock()方法 ])
  • 实现Runnable接口解决线程安全问题(代码块)
/**
 * Runnable通过同步代码块的方式实现线程安全问题
 */
private int ticket = 100;
private Object obj = new Object();
@Override
public void run() {
        while (true){
            //synchronized(this)
    		synchronized(obj){
            if(ticket > 0){
                ticket--;
                System.out.println(Thread.currentThread().getName() + "购票成功! 剩余票数:" + ticket);
            }else {
                break;
            }
        }
    }
}

    public static void main(String[] args) {
        RunnableTicket runnableTicket = new RunnableTicket();
        new Thread(runnableTicket).start();
        new Thread(runnableTicket).start();
    }
  • 同步方法 加上synchronized 关键字
/**
 * Runnable通过同步方法的方式实现线程安全问题
 */
private int ticket = 100;
@Override
public void run() {
    while(true){
    	show();  
    }
}

private synchronized void show(){
        if(ticket > 0){
            ticket--;
            System.out.println(Thread.currentThread().getName() + "购票成功! 剩余票数:" + ticket);
        }else {
            break;
        }
}
  • 继承Thread解决线程安全问题(代码块)
private static int ticket = 100;
private static Object obj = new Object();
@Override
public void run() {
        while (true){
            //synchronized(ThreadTick.class)
    		synchronized(obj){
            if(ticket > 0){
                ticket--;
                System.out.println(Thread.currentThread().getName() + "购票成功! 剩余票数:" + ticket);
            }else {
                break;
            }
        }
    }
}

public static void main(String[] args) {
	new ThreadTicket().start();
	new ThreadTicket().start();
}
  • 同步方法
private static int tickets = 100;
@Override
public void run() {
    while (true){
        show();
    }
}

/**
 * 因为静态方法随着类的加载而加载且只加载一次,所以锁是唯一的
 *
 * 拓展复习: 静态代码块随着类的加载而加载,且主动执行
 *           非静态代码块随着类对象的创建而加载,且主动执行
 */
private static synchronized void show(){
    if(tickets > 0){
        tickets--;
        System.out.println("售票成功! 当前乘车人:" + Thread.currentThread().getName() + ",剩余票数:" + tickets);
    }else {
        return;
    }
}
  • 例题:两个账户向另一个账户汇款各3000元,共3次
public class ImportMoney {
    private static int money = 0;
	//第三种:Object obj = new Object()
    
    //第一种
    public synchronized void getMoney(int getMoney){
        if(getMoney > 0){
            money += getMoney;
            System.out.println("当前余额: " + money + ",汇款账户:" + Thread.currentThread().getName());
        }else {
            return;
        }
    }
    
    //第二种
    public void getMoney(int getMoney){
        synchronized(this){
            if(getMoney > 0){
                money += getMoney;
                System.out.println("当前余额: " + money + ",汇款账户:" + Thread.currentThread().getName());
            }else {
                return;
            }
        }
    }
    
    //第三种,通过对象监视器的方式 synchronized(obj)
}




public class ImportMoneyTest {
    public static void main(String[] args) {
        //当前类对象in 作为唯一的锁
        ImportMoney in = new ImportMoney();
        new Export(in).start();
        new Export(in).start();
    }
}


class Export extends Thread{
    //作为唯一的锁
    private ImportMoney importMoney;

    public Export(ImportMoney importMoney){
        this.importMoney = importMoney;
    }

    @Override
    public void run() {
        for (int i = 0; i <3 ; i++) {
            importMoney.getMoney(1000);
        }
    }
}
5线程的通信
public class MyWait implements Runnable {
    private int num = 1;
    @Override
    public void run() {
        while (true){
            synchronized (this){
                //唤醒进入阻塞的线程
                notify();
                if(num <= 100){
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    try {
                        //进入阻塞状态,并释放cpu执行权,而sleep()不会释放,一致处在阻塞占用资源状态
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }
}
6 JDK5.0新增线程创建方式(共4种)
  • 3.实现Callable接口
    public class MyCallable implements Callable {
        @Override
        public Object call() throws Exception {
            int num = 10;
            return num;
        }
    }
    
    
    public class MyCallableTest  {
        public static void main(String[] args) {
            //3.创建Callable接口实现类的对象
            MyCallable myCallable = new MyCallable();
            //4.将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask对象
            FutureTask futureTask = new FutureTask(myCallable);
            //5.将futureTask作为参数,通过Thread启动线程
            new Thread(futureTask).start();
    
            try {
                //6.获取Callable中call方法的返回值
                Object o = futureTask.get();
                System.out.println(o);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值