Java多线程编程

Java多线程

  1. 一个进程最多可以创建1000个线程,开一个线程大概要消耗1M的内存,超过这个线程数字将会出现线程泄漏。
  2. 时间片轮转机制
java中的Thread是对线程对象的唯一抽象,Runnable Callable 是对任务的抽象,一个线程里面可以执行很多的任务,例如UI线程 workthread线程 就是一个线程执行的多个任务。

Start方法只能调用一次,不能同时调用两次,会报错(IllegalThreadStateException)。而run就是一个成员函数,可以调用无数次。

/**使用
扩展Thread 类,复写其run方法。
*/
private static class UserThread extends Thread {
    @Override
    public void run() {
        System.out.println("TestThread");
    }
}
/**
* 实现Runnable任务对象,但是没有接口
*/
private static class UseRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(" this is Runnable");
    }
}
/*实现Callable 泛型接口 ,允许有返回值*/
private static class UseCallable implements Callable<String>{

    @Override
    public String call() throws Exception {
        return " this is a UseCallable";
    }
}

public static void main(String[] args) throws ExecutionException, InterruptedException {
    UserThread testThread = new UserThread();
    testThread.start();

    UseRunnable useRunnable = new UseRunnable();
    new Thread(useRunnable).start();

    FutureTask<String> futureTask = new FutureTask(new UseCallable());
    new Thread(futureTask).start();

    System.out.println(" UseCallable futureTask.get(); " + futureTask.get());
}
创建 thread 对象,传入的是一个Runnable接口,所以实现这个接口的对象都可以作为参数。
public Thread(Runnable target) {}
FutureTask  extends Runnable, Future<V>{}
构造函数:
public FutureTask(Callable<V> callable) {}
public FutureTask(Runnable runnable, V result) {}

public interface Future<V> {
    
    boolean cancel(boolean var1);

    boolean isCancelled();
   
    boolean isDone();
  //获取线程的返回值
    V get() throws InterruptedException, ExecutionException;

    V get(long var1, TimeUnit var3) throws InterruptedException, ExecutionException, TimeoutException;
}

注意下面的run方法是在主线程中执行,run和一般的成员函数回调是一样的。
新线程的创建是在Start()方法后创建。run()会立即执行.

private static class UserThread extends Thread {
   @Override
   public void run() {
       System.out.println("I am :" + Thread.currentThread() + " thread");
   }
}
public static void main(String[] args) {
   UserThread testThread = new UserThread();
   testThread.run();
   }
   执行结果:I am ��Thread[main,5,main] thread 

线程的优先级特别不靠谱,所以在架构的时候一般不使用线程的优先级来保证线程的执行顺序。
而是用jion() 方法来执行。

wait 和notify notifyAll 。

注意 wait 是主动将自己持有的锁释放的。
notify 不能去指定唤醒某一个线程。
一般的格式是:
syn(对象){
while (条件不满足) {
对象. wait();
}
执行业务代码
}

syn (对象) {
修改上面的条件
对象.notify /notifyAll;
}

syn 是内置锁,一旦某个线程开始获取锁的时候,但是这个锁被别的线程持有的时候,它将处于等待状态,线程获取锁的过程是不能被中断的,他会一直处于等待状态。所以时间长了会出现ANR
显示锁—Lock锁

获取锁的过程可以被中断

//他是一个接口:
public interface Lock {

ThreadLocal 讲解

每个线程里面都保存有一个ThreadLocalMap类型的变量。
每个线程不同,线程中包含的ThreadLocalMap对象不同
这样才是线程安全的。都是单独隔离出来的。

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
每个线程都会创建一个新的ThreadLocalMap对象赋值给每个线程的threadLocals 对象。就是说每个线程中都会拥有一个
ThreadLocalMap类型的变量,这个变量保存有给此threadLocal 设定的值(Value)。Key值为threadLocal对象。每个线程的Key值是一样的,Value值不同。
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

在Thread类中包含有:
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap 类中就包含有Entry[] table;
每个Entry[]数组里面的值就是(ThreadLocal<?> k, Object v)键值对。
所以出现在同一个线程中会出现
ThreadLocal1=value1
ThreadLocal2
=value2 同一个线程都互不干扰

可重入锁ReentrantLock

Re—entrant ----Lock (可以重复—进入–锁 )
synchronized 内部自己实现了可重入锁机制,这样当出现递归循环调用的时候,可以重复拿到锁,不会出现异常。可重入的锁可以防止自己拿自己的锁 出现死锁。synchronized 是非公平锁

public synchronized void inc(){
    count++;
    if (count == 10) {
        return;
    }
    inc();
}
// 如果是true 就是公平锁,
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
ReentrantReadWriteLock 可重入的读写锁

ReentrantReadWriteLock 里面有两把锁,读的时候可以有多线程同时读,但是不能有线程来写。
在写的时候,不允许有别的线程来读和别的线程来写。

线程的6种状态

  1. 初始状态
  2. 运行状态(其中包含 就绪状态 / 运行状态, 如果当前线程被分配了时间片,他拿到了CPU 它就处于运行状态。如果它的时间片用完 或者被操作系统剥夺了 就会处于就绪状态)
  3. 等待状态, 如果在运行状态调用wait() 进入 等待状态,如果唤醒 从等待切换到运行状态
  4. 运行超时状态, 如果在运行状态下调用wait(long) 就是进入等待超时状态,时间到了就会自动回到运行状态
  5. 阻塞状态, 当前的线程调用了synchronized修饰的代码块,如果没有拿到锁,就会进入到阻塞状态,只有重新拿到锁,就会再次处于运行状态。
  6. 线程执行完就会终止状态

出现死锁的时候程序没有什么异常日志出现,程序会卡住不动,只有将程序退出才会恢复。
死锁的条件:
7. 互斥条件
8. 请求保持
9. 不剥夺
10. 环路等待

破坏锁的条件是1. 破坏锁的拿锁顺序
2. 拿到资源以后允许放手

活锁:
两个线程一直在拿锁 释放锁,但是两个一直都在这样的过程中操作

ThreadLocal 是线程本地变量,也叫线程本地存储。 ThreadLocal 可以让每个线程拥有一个属于自己的变量的副本,不会和其他线程的变量副本冲突,实现了线程的数据隔离。

一个类里面的静态内部类和外部类没有任何关系
static 变量在虚拟机就一份

.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值