• Java高并发-多线程基础


    一、什么是线程

    线程是进程内的执行单元。

    二、线程的基本操作

    2.1 状态与操作

    2.2 新建线程

    Thread t1 = new Thread(new CreateThread());
    t1.start();
    
    # 直接覆盖run方法
    # 传target实例,即Runnable接口实例
    

    2.3 终止线程

    2.4 中断线程

    public void Thread.interrupt(); // 中断线程
    public boolean Thread.isInterrupted(); // 判断是否被中断
    public static boolean Thread.interrupted(); // 判断是否被中断,并清除当前中断状态
    
    public static native void sleep(long millis) throws InterruptedException
    

    代码

    // 线程t1
    public void run() {
        while(true) {
            Thread.yield();
        }
    }
    // 对线程t1进行中断操作,线程t1并不会做出响应
    t1.interrupt();
    
    // 执行下面这段代码的线程,会对中断做出响应
    public void run() {
        while(true) {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("Interrupted!");
                break;
            }
            Thread.yield();
        }
    }
    

    sleep代码

    // 在等待的过程中,也对中断操作做出响应
    public void run() {
        while(true) {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println('Interrupted!');
                break;
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                System.out.println("Interrupted When Sleep");
                // 设置中断状态,抛出异常后会清除中断标记位
                Thread.currentThread().interrupt();
            }
            Thread.yield();
        }
    }
    

    2.5 挂起和继续执行线程

    suspend()不会释放锁

    如果加锁发生在resume()之前,则发生死锁

    这两个就法不推荐使用

    模拟死锁:

    public class BadSuspend {
    	public static Object u = new Object();
    	static ChangeObjectThread t1 = new ChangeObjectThread("t1");
    	static ChangeObjectThread t2 = new ChangeObjectThread("t2");
    	public static class ChangeObjectThread extends Thread {
    		public ChangeObjectThread(String name) {
    			super.setName(name);
    		}
    		@Override
    		public void run() {
    			synchronized(u) {
    				System.out.println("in " + getName());
    				Thread.currentThread().suspend();
    			}
    		}
    	}
    	public static void main(String[] args) throws InterruptedException {
    		t1.start();
    		Thread.sleep(100);
    		t2.start();
    		t1.resume();
    		t2.resume();
    		t1.join();
    		t2.join();
    	}
    }
    

    分析:

    t1线程正常结束,t2线程死锁

    2.6 等待线程结束和谦让

    join,yeild

    // 把自己占用的CPU机会释放掉,再和别人一起竞争CPU
    public static native void yield();
    
    // 当前线程未做完,主线程等待当前线程做完后再往下走
    public final void join() throws InterruptedException
    public final synchronized void join(long millis) throws InterruptedException
    

    三、守护线程

    在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程

    当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出

    四、线程优先级

    高优先级的线程更容易在竞争中获胜

    t1.setPriority(Thread.MAX_PRIORITY);
    

    五、基本的线程同步操作

    5.1 synchronized

    指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

    直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

    直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

    指定加锁对象

    public class AccountingSync implements Runnable {
    	static AccountingSync instance = new AccountingSync();
    	static int i = 0;
    	@Override
    	public void run() {
    		for (int j=0;j<100000;j++) {
    			synchronized(instance) {
    				i++;
    			}
    		}
    	}
    	public static void main(String[] args) throws InterruptedException {
    		Thread t1 = new Thread(instance);
    		Thread t2 = new Thread(instance);
    		t1.start(); 
    		t2.start();
    		t1.join();
    		t2.join();
    		System.out.println(i);
    	}
    }
    

    作用于实例方法:注意多个线程要对同一个实例加锁

    public class AccountingSync2 implements Runnable {
    	static AccountingSync2 instance = new AccountingSync2();
    	static int i = 0;
    	public synchronized void increase() {
    		i++;
    	}
    	@Override
    	public void run() {
    		for (int j=0;j<100000;j++) {
    			increase();
    		}
    	}
    	public static void main(String[] args) throws InterruptedException {
    		Thread t1 = new Thread(instance);
    		Thread t2 = new Thread(instance);
    		t1.start(); 
    		t2.start();
    		t1.join();
    		t2.join();
    		System.out.println(i);
    	}
    }
    
    

    作用于静态方法:注意区别 作用于实例方法

    5.2 wait()/notify()

    notify()之后,允许线程往下走,但是如果没有获得锁的话,也还是执行不了,t2.notifyAll()之后t1就可以往下执行了,但是此时t1还未获得object锁,必须等t2睡2秒后,获得object锁后执行。

  • 相关阅读:
    左旋一个字符串和手摇反转法
    LCS
    游戏服务器学习_1
    面试题_带答案_2
    面试题_带答案
    安卓_13
    安卓_12activity
    安卓_12
    多盟_1
    安卓没删干净导致报错
  • 原文地址:https://www.cnblogs.com/okokabcd/p/8721053.html
Copyright © 2020-2023  润新知