首页 > 编程语言 >Java 知识 复习

Java 知识 复习

时间:2023-10-13 18:34:00浏览次数:42  
标签:Java 复习 Thread lock 知识 Callable 线程 public pool

1. 并发编程

下面的程序需要导入 java.util.concurrent.*

1.1 用户线程 (四种方式)

创建用户线程的方式有4种,分别是 继承 Thread类、实现 Runnable 接口、实现 Callable 接口、以及使用线程池。

1.1.1 继承自 Thread 类

这种方式比较简单,通过继承 Thread 类,并重写 run() 方法。在使用的时候 实例化并调用 start() 方法即可。

public class MyMain {
    public static void main(String[] args) {

        MyThread myThread = new MyThread();
        myThread.start();
    }
}

class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println("继承自Thread创建线程!");
    }
}

1.1.2 实现 Runnable 接口

实现 Runnable 接口并重写 run()方法,但由于没有 start() 方法启动线程,所以需要借助 Thread 来启动。

public class MyMain {
    public static void main(String[] args) {

        Runnable myRunnableImpl = new MyRunnableImpl();

        Thread thread = new Thread(myRunnableImpl);
        thread.start();
    }
}

class MyRunnableImpl implements Runnable{

    @Override
    public void run() {
        System.out.println("实现Runnable创建线程!");
    }
}

1.1.3 实现 Callable 接口

通过实现 Callable 接口创建线程。
与 Runnable 接口的不同:

  • Callable 需要重写的是 call() 方法
  • Callable 有返回值,所以需要借助 FutureTask 这个容器用于获取结果
  • 注意 通过 FutureTask 容器获取计算结果的方法 get() 会有异常抛出
public class MyMain {
    public static void main(String[] args) {

        Callable<String> myCallable = new MyCallableImpl();

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

        try{
            String result = futureTask.get();
            System.out.println(result);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

class MyCallableImpl implements Callable<String>{

    @Override
    public String call(){

        System.out.println("实现Callable接口创建线程!");
        return "这是 call 方法的返回值!";
    }
}

小结

以上三种方式创建线程,最后都是通过 Thread 进行执行。Callable 有结果返回,所以用 FutureTask 容器保存,但最后也还是交由 Thread 执行。

1.4 线程池创建线程

这种方式避免了线程的反复创建和销毁。
首先通过 Executors 工具类的 newFixedThreadPool() 创建线程池(ExecutorsService)
ExecutorsService 内有两个成员方法可以提交线程,分别是 submit() 和 execute()
区别:

  • 方法的参数
    • submit() 方法 接受的变量可以是 Runnable、Callable、Thread
    • execute() 方法 不能接受 Callable
  • 返回值
    • submit() 方法的返回值为 Future,可以接受 Callable 的 call 方法的返回值
    • execute() 方法无返回值

最后,线程池使用结束,可以使用 shutDown() 方法关闭线程池

public class MyMain {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        ExecutorService pool = Executors.newFixedThreadPool(5);

        Callable<String> myCallable = new MyCallableImpl();
        Runnable myRunnable = new MyRunnableImpl();
        Thread myThread = new MyThread();

        // submit 可以获取结果
        Future<String> result = pool.submit(myCallable);
        System.out.println(result.get());

        // execute 无返回结果
        pool.execute(myRunnable);
        pool.execute(myThread);


        // 关闭线程池
        pool.shutdown();
    }
}

1.2 守护线程

守护线程,俺一开始以为它是个很强的玩意,守护嘛。但实际上它对于程序而言似乎并不是那么重要。
守护线程,如果其它用户线程(非守护线程)终止了,那么守护线程也就终止,与守护线程是否执行完成没有关系。所以一般用于执行一些任务、服务,如定期缓存清理等。
因为守护线程随时都可能被中止,不能保证完整性,所以守护线程不用于实现一些关键业务逻辑。而且,守护线程的优先级低,通常低于用户线程,所以,资源优先提供给用户线程。

通过 Thread 的成员方法 setDaemon(true) 可以将线程设置为守护线程。
值得注意:守护线程需要在用户线程启动后才能启动,否则会发送 IllegalThreaStatusException 异常

public class MyMain {
    public static void main(String[] args){

        Thread myThread = new MyThread();
        
        myThread.setDaemon(true);
        myThread.start();
    }
}

2. Java 锁机制

Java 的锁机制,这里将简单介绍 synchronized关键字、ReentrantLock、ReadWriteLock
后两个需要 import java.util.concurrent.locks.*;

2.1 synchronized关键字

synchronized 关键可以修饰方法,也可以作用在对象上。

public class MyMain {
    public static void main(String[] args) {

        Thread thread = new MyThread();

        ExecutorService pool = Executors.newFixedThreadPool(12);
        pool.execute(thread);
        pool.execute(thread);
        pool.execute(thread);
        pool.execute(thread);
        pool.execute(thread);

        pool.shutdown();
    }
}

class MyThread extends Thread{
    private static Integer num = 10;

    @Override
    public void run() {
        while (sell());
    }

    private synchronized boolean sell(){

        if (num<=0)
            return false;

        System.out.printf("%s---%d\n",Thread.currentThread().toString(),num);
        num -= 1;

        return true;
    }
}
class MyThread extends Thread{
    private static Integer num = 1000;

    @Override
    public void run() {
        while (sell());
    }

    private boolean sell(){

        if (num<0)
            return false;

        synchronized (num){
            System.out.printf("%s---%d\n",Thread.currentThread().toString(),num);
            num--;
        }

        return true;
    }
}

2.2 ReentrantLock

使用ReentrantLock,需要在实例化的时候传入 ReentrantLock对象,需要上锁的时候,调用 lock.lock(),解锁的时候使用 lock.unlock() 即可。

public class MyMain {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();

        Runnable myRunnable = new MyRunnableImpl(lock);
        ExecutorService pool = Executors.newFixedThreadPool(5);

        pool.execute(myRunnable);
        pool.execute(myRunnable);
        pool.execute(myRunnable);

        pool.shutdown();
    }
}

class MyRunnableImpl implements Runnable{
    private static Integer num = 100;
    private final ReentrantLock lock;

    MyRunnableImpl(ReentrantLock lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        while (sell());
    }

    private boolean sell(){

        lock.lock();
        try{
            if (num<0)
                return false;
            
            System.out.printf("%s---%d\n",Thread.currentThread().toString(),num);
            num--;
        }finally {
            lock.unlock();
        }

        return true;
    }
}

2.3 ReentrantReadWrite

这是读锁和写锁,允许多个线程同时持有读锁,但只允许一个线程持有写锁。

public class MyMain {
    public static void main(String[] args) {

        ReadWriteLock lock = new ReentrantReadWriteLock();

        Callable<String > myCallable = new MyCallableImpl(lock);
        ExecutorService pool = Executors.newFixedThreadPool(5);

        pool.submit(myCallable);
        pool.submit(myCallable);
        pool.submit(myCallable);

        pool.shutdown();
    }
}

class MyCallableImpl implements Callable<String>{
    private static Integer num = 100;
    private ReadWriteLock lock;

    MyCallableImpl(ReadWriteLock lock){
        this.lock = lock;
    }
    @Override
    public String call() throws Exception {
        while (sell());
        return null;
    }

    public boolean sell(){

        lock.readLock().lock();
        try {
            if (num<0)
                return false;
        }finally {
            lock.readLock().unlock();
        }

        lock.writeLock().lock();
        try{
            System.out.printf("%s****%d\n",Thread.currentThread(),num);
            num--;
        }finally {
            lock.writeLock().unlock();
        }
        return true;
    }
}

标签:Java,复习,Thread,lock,知识,Callable,线程,public,pool
From: https://www.cnblogs.com/welcome-to-future/p/17762891.html

相关文章

  • 能否翻译翻译,到底什么才叫“精通Java” ?
    01 模糊的岗位能力标准 技术类人员的招聘始终是令HR与技术面试官头疼的事。在一般招聘流程中,当确定了某个岗位招聘需求后,技术面试官会与HR一同商讨并明确该岗位的画像。明确画像后,一般HR会负责在招聘平台书写岗位JD,技术面试官则会准备相应的笔面试题目来考核岗位所要的能......
  • Java学习笔记二
    Java学习笔记二面向对象(ObjectOriented)属性(成员变量)跟随对象放在堆里面,局部变量(如p1)放在栈里面。只有成员变量的前面能添加权限修饰符,且成员变量自带默认值。在一个类中,一个方法可以调用这个类中的其余方法(包括自身,即递归)以及成员变量,不能在方法中再定义方法。方法重载(O......
  • 在Eclipse将Java代码打包为jar用于jmeter BeanShell
    Beanshell是java的轻量级脚本,可以直接引用java代码,有下面3种方式:1、直接输入java代码2、导入java文件(或者导入class文件)3、导入jar文件现在记录第三种方式,导入jar文件第一步是先在Eclipse将Java代码打包为jar1、先准备好需要打包的代码 2、首先在Eclipse中选中需要打包......
  • 在Eclipse将Java代码打包为jar用于jmeter BeanShell(HMAC_SHA1)加密
    Eclipse代码importjavax.crypto.Mac;importjavax.crypto.SecretKey;importjavax.crypto.spec.SecretKeySpec;importjava.nio.charset.StandardCharsets;importjava.security.InvalidKeyException;importjava.security.NoSuchAlgorithmException;publicclassHMAC_data......
  • 简单工厂模式--Java实现+C++实现
    问题描述使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果传入参数M,则返回一个Man对象,如果传入参数W,则返回一个Woman对象,如果传入参数R,则返回一个Robot对象。请用程序设计实现上述场景。问题实现用starUML画的相应的类图:然后就是代码实现:Java代码实现在Java里面,Person类相......
  • 将java程序,安装为windows服务,开机自启动
    借助WindowsServiceWrapper小工具,将java程序转换为Windows服务,在服务中心配置自启动,从而在开机时windows自行启动服务。WindowsServiceWrapper下载URL:https://github.com/winsw/winsw/releases如下图,为windows32位和64位的工具文件 32位:链接: https://pan.baidu.co......
  • 基于知识图谱建模、全文检索的智能知识管理库(源码)
    一、项目介绍一款全源码,可二开,可基于云部署、私有部署的企业级知识库云平台,一款让企业知识变为实打实的数字财富的系统,应用在需要进行文档整理、分类、归集、检索、分析的场景。知识图谱提供了一种从海量文本和图像中抽取结构化知识的手段,让知识获取更便捷、知识整理更简单、知......
  • java运行时数据区
    Java运行时数据区域  众所周知,Java虚拟机有自动内存管理机制,如果出现内存泄漏和溢出方面的问题,排查错误就必须要了解虚拟机是怎样使用内存的。包含:程序计数器(PC)、堆、本地方法栈、虚拟机栈、元空间  下图是JDK8之后的JVM内存布局。程序计数器(PC)内存中一块较小的空......
  • 配置Tomcat运行Java Web项目
    创建项目创建JavaWeb项目ctrl+shift+p打开搜索Maven原型,并选择从maven原型创建新项目或者按如下方式:选择从Maven原型创建Web项目从maven-archetype-webapp原型创建项目接着选择原型版本、输入包名、项目名、选择项目存放位置注意:到此需要按一下回车来继续输入Y或者回......
  • Java流(Stream)、文件(File)和IO
    Java流(Stream)、文件(File)和IOJava流(Stream)、文件(File)和IOjava.io包几乎包含了所有操作输入、输出需要的类所有这些流类流类代表了输入源和输出目标Java.io包中的流支持很多种格式比如:基本类型、对象、本地化字符集等等一个流可以理解为一个数据的序列输入流表示从一......