您好,欢迎来到叨叨游戏网。
搜索
您的当前位置:首页Java基础七-线程相关

Java基础七-线程相关

来源:叨叨游戏网

创建一个线程

Java 提供了三种创建线程的方法:

  • 通过implements Runnable 接口;
  • 通过extends Thread 类本身;
  • 通过 Callable 和 Future 创建线程。
1. 线程创建对比
1. 采用实现 Runnable、Callable 接口的方式创建多线程时,
线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
优点还可以实现其他接口。
步骤:创建implements的实例A,再创建Thread实例,传入实例A;
重写run方法,调用start()方法


2. 使用继承 Thread 类的方式创建多线程时,编写简单,
如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,
直接使用 this 即可获得当前线程。
缺点是不能继承其他类,如果需要继承就会有类的继承层次问题。
步骤:extends Thread类,重写run()方法,New一个线程之后,调用start()
2. 线程创建栗子
  • Thread
package basic;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class ThreadTest extends Thread{
    //定义私有变量,存储线程名称
    private String threadName;
    //线程构造方法,接受了参数'name',并且传递给threadName,声明了线程名称
    public ThreadTest(String name){
        threadName = name;
        System.out.println("Creating " +  threadName );
    }

    //重写了run方法,里面是具体的执行内容
    @Override
    public void run(){
        System.out.println(threadName +" is running");
        HashMap<String, Integer> map = new HashMap<>();
        map.put("111",1);
        map.put("222",2);

        Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<String,Integer>> iterator = entrySet.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Integer> entry = iterator.next();
            System.out.println("Thread: " + threadName + ", Map key is-->" + entry.getKey());
        }



    }


    public static void main(String[] args) {
        // 实现了ThreadTest,并且创建了线程T1和T2,使用start()并行执行
        ThreadTest T1 = new ThreadTest( "Thread-1");
        T1.start();

        ThreadTest T2 = new ThreadTest( "Thread-2");
        T2.start();
    }


}



  • Runnable
package basic;

public class RunnableTest implements Runnable {
    private String threadName;

    public RunnableTest(String name){
        threadName = name;
        System.out.println("creating : " + threadName);
    }

    @Override
    public void run() {
        System.out.println("this is running run method: " + threadName);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sleep end -->" + threadName);
    }

    public static void main(String[] args) {
        // 创建RunnableTest实例
        RunnableTest runnable1 = new RunnableTest("Runnable-1");
        RunnableTest runnable2 = new RunnableTest("Runnable-2");

        // 创建Thread实例,传入Runnable实例作为参数
        Thread t1 = new Thread(runnable1);
        Thread t2 = new Thread(runnable2);
        
        t1.start();
        t2.start();

    }
}
  • Callable

实现Callable类,call()方法有返回值

3. 并发和并行
1. 并行是发生在多个实体身上,并发是发生在同一个实体身上
2. 并行是在多个实体同一时刻同时发生,如hadoop分布式集群。
   并发是只有一个实体在同一时刻逐个发生
4. 程序、进程、线程
1. 程序:有至少一个进程构成,程序通常由源代码编写而成,可以是用高级编程语言编写的,需要经过编译或解释后才能在计算机上运行。
2. 进程:进程最少由一个线程构成,每个线程都有自己的内存空间,包括代码、数据、堆栈等。
    进程之前互相,不受影响
3. 线程:线程构成进程,多线程共享进程的内存空间。线程之间切换更快

5. 守护线程

thread.setDaemon(true); // 设置为守护线程
守护线程不是程序的线程,是个服务线程,准确地来说就是服务其他的线程。例如计时、垃圾回收等
6. 线程的状态
线程一共有准备、就绪、运行、阻塞、死亡5个状态
1. 准备:实现了Thread()类之后,没有执行start()之前
2. 就绪:执行了start()之后,但是没有运行,可能是当前执行的线程并非执行start()的线程
3. 运行:允许当前的线程是就绪状态的线程,执行了run()方法
4. 阻塞:线程在等待(执行sleep)、或者访问资源被占用的时候
5. 死亡:线程结束或者执行stop()
7. sleep() 和 wait() 
1. sleep()
    sleep()属于Thread类的方法,线程调用sleep()方法后,会锁定线程资源
不会被占用,直到sleep结束才释放锁资源

2. wait()
    wait()属于Object()类的方法,必须在同步块synchronized 代码块中调用。
并且调用之后当前线程进入暂停,释放锁资源。处于对象的等待池之中。
当前线程只能通过其他该对象的其他线程使用notify()\notifyAll()唤醒
8. notify()和notifyAll()
notify()是把对象线程等待池中的随机一个线程唤醒
notifyAll()是把对象等待池中的所有线程唤醒

这两个方法都必须在同步块(或同步方法)内部调用
9. 创建线程的方法
1. 使用 Executors 工厂类
// 创建一个固定长度的线程池,适用于需要并发线程数量的场景,适合控制资源的使用。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
// 创建可缓存的线程池,不够增加,多了回收
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 创建单线程
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 适用于需要按计划执行任务的场景,可以安排延迟执行或者周期性执行。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

10. submit和execute
1. submit()有返回值,Future<?>,可以捕获线程执行结果或者异常。用于Runnable和Callable类
2. execute()没有返回值,只能用于Runnable
11. 怎么保障线程安全
1. 原子性:保障数据的访问只有一个线程
2. 可见性:对内存的修改,可以被其他线程看到
3. 有序性:线程可以观察到其他线程的执行顺序,然后用于重新排序
12. synchronized
线程同步锁,synchronized锁包含的代码块,只允许一个线程访问
13. synchronized和volatile 
synchronized 和 volatile 的区别
1. synchronized满足锁的三元素:原子性、可见性、有序性
    重量级,可能会导致阻塞,性能较差
2. volatile只满足可见性和有序性。轻量级,不会导致锁

3. volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。

14. synchronized 和 Lock 
synchronized 和 Lock 区别
1. synchronized是java 的一个内置关键字,Lock是一个java类
2. 结束:synchronized会在线程运行结束后自动结束,而Lock是在finally里面调用unlock()方法
3. 适用范围:synchronized适用在小的代码块,Lock适用高并发复杂场景
4. 异常处理:synchronized如果线程A阻塞,线程B则会一直等待。
            Lock中线程B不会等待直接结束
15. atomic 的原理
1. 通过CAS实现,三元素:内存地址,期望值,更新值;
当获取到的内存地址与期望值不匹配,会更新对应的更新值
2. 排它性:只允许一个线程访问对象,其他线程一直是循环
等待状态,只有当释放了资源才会允许访问

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- gamedaodao.net 版权所有 湘ICP备2024080961号-6

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务