Java多线程开发--线程常用操作方法

内容学习于:edu.aliyun.com


1. 线程的取名和获得

  多线程的运行状态是不确定的,那么在程序的开发之中为了可以获取到一些需要使用到线程就只能够依靠线程的名字来进行操作。所以线程的名字是-一个至关重要的概念,这样在Thread类之中就提供有线程名称的处理:

  • 构造方法:public Thread(Runnable target , String name);
  • 取得名字: public final String getName()
  • 设置名字:public final void setName(String name)

  对于线程对象的获得是不可能只是依靠一个this来完成的,因为线程的状态不可控,但是有一点是明确的,所有的线程对象一定要执行run()方法,那么这个时候可以考虑获取当前线程,在Thread类里面提供有获取当前线程的方法:

  • 获取当前线程:public static Thread currentThread()

代码:

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

public class Demo1 {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "线程A").start();//设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt, "线程B").start();//设置线程名字
    }
}

结果:

线程A
线程B
Thread-0

  当开发者为线程设置名字的时候就使用设置的名字,而如果没有设置名字,则会自动生成一个不重复的名字,这种自动的属性命名主要是依靠了static属性完成的。

代码:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
        new Thread(mt).start();//没有设置线程名字
    }
}

结果:

Thread-0
Thread-3
Thread-4
Thread-1
Thread-2

自动命名原理:

  在Thread类里面定义有如下操作:

private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}

代码:

//对象直接调用run()方法
public class Demo1 {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt,"线程对象").start();//设置线程名字
        mt.run();//对象直接调用run()方法
    }
}

观察下面代码:

public class JavaDemo
{
	public static void main(String args[]){
		for(int x= 0; x< Integer.MAX_VALUE;x++){
			System.out.println();
		}
	}
}	

  进程如下图所示:在这里插入图片描述
  每当启动一个JVM就会启动一个进程,每个主方法都是主进程
在任何的开发之中,主线程可以创建若干个子线程,创建子线程的目的是可以将一些复杂逻辑或者比较耗时的逻辑交由子线程处理;

代码:

例子1:
public class Demo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("1、执行任务一");
        int temp = 0;
        for (int x = 0; x < Integer.MAX_VALUE; x++) {
            temp += x;
        }
        System.out.println("2、执行任务二");
        System.out.println("n、执行任务N");
    }
}

  从结果上看,后续的任务会延迟出现

例子2:
//子线程处理
public class Demo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("1、执行任务一");

        new Thread(() -> {//子线程负责统计
            int temp = 0;
            for (int x = 0; x < Integer.MAX_VALUE; x++) {
                temp += x;
            }
        }).start();

        System.out.println("2、执行任务二");
        System.out.println("n、执行任务N");
    }
}

  主线程负责处理整体流程,而子线程负责处理耗时操作,这样将不影响后续的任务进行。

2. 线程的休眠

  如果说现在希望某一个线程可以暂缓执行,那么就可以使用休眠的处理,在Thread类之中定义的休眠方法如下:

  • 休眠:public static void sleep(long millis) throws InterruptedException
  • 休眠:public static void sleep(long millis,int nanos) throws InterruptedException

  在进行休眠的时候有可能会产生中断异常“InterruptedException", 中断异常属于Exception 的子类,所以证明该异常必须进行处理。

线程休眠代码:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        new Thread(() -> { 
            for (int x = 0; x < 10; x++) {
                System.out.println(Thread.currentThread().getName() + "、x=" + x);
                try {
                    Thread.sleep(1000);//暂缓执行
                } catch (InterruptedException e) {//必须处理中断异常
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

  休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续的处理。但是需要注意的是,如果现在有多个线程对象,那么休眠也是有先后顺序的。

产生多个多个对象进行休眠处理:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        for (int num = 0; num < 5; num++) {
            new Thread(() -> {
                for (int x = 0; x < 10; x++) {
                    System.out.println(Thread.currentThread().getName() + "、x=" + x);
                    try {
                        Thread.sleep(1000);//暂缓执行
                    } catch (InterruptedException e) {//必须处理中断异常
                        e.printStackTrace();
                    }
                }
            }, "线程" + num).start();
        }
    }
}

  此时将产生五个线程对象,并且这五个线程对象执行的方法体是相同的。此时从程序执行的感觉上来讲好像是若千个线程一起进行了休眠,而后一起进行了自动唤醒,但是实际上是有差别的。
如下图所示:在这里插入图片描述

3. 线程中断

  在之前发现线程的休眠里面提供有一个中断异常,实际上就证明线程的休眠是可以被打断的,而这种打断肯定是由其它线程完成的,在Thread类里面提供有这种中断执行的处理方法:

  • 判断线程是否中断:public static boolean interrupted()
  • 中断线程执行:public void interrupt()

线程中断代码:


public class Demo1 {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            System.out.println("***准备睡觉了***");
            try {
                Thread.sleep(10000);//准备睡10秒
            } catch (InterruptedException e) {
                System.out.println("【敢不让我睡觉???】");
            }
            System.out.println("睡够了!!!");
        });
        thread.start();//开始线程
        Thread.sleep(1000);//先休眠1秒钟
        if (!thread.isInterrupted()) {//判断线程是否中断执行
            System.out.println("【我就轻轻的打扰一下】");
            thread.interrupt();//中断线程
        }
    }
}

结果:

***准备睡觉了***
【我就轻轻的打扰一下】
【敢不让我睡觉???】
睡够了!!!

  所有正在执行的线程都是可以被中断的,中断线程必须进行异常的处理。

4. 线程强制执行

  所谓的线程的强制执行指的是当满足于某些条件之后,某一个线程对象将可以一直独占资源,一直到该线程的程序执行结束。

代码:

public class Demo1 {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            for (int x = 0; x < 3; x++) {
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "玩耍的子线程");
        thread.start();//开始线程
        for (int x = 0; x < 3; x++) {
            System.out.println("【霸道的主线程】执行、x=" + x);
        }
    }
}

结果:

【霸道的主线程】执行、x=0
【霸道的主线程】执行、x=1
【霸道的主线程】执行、x=2
玩耍的子线程执行、x=0
玩耍的子线程执行、x=1
玩耍的子线程执行、x=2

  这个时候主线程和子线程都在交替执行着,但是如果说现在你希望主线程独占执行。那么就可以利用Thread类中的方法:

  • 强制执行:public final void join() throws InterruptedException

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int x = 0; x < 5; x++) {
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "玩耍的子线程");
        thread.start();//开始线程
        for (int x = 0; x < 5; x++) {
            if(x==2){
                thread.join();//子线程强行执行
            }
            System.out.println("【霸道的主线程】执行、x=" + x);
        }
    }
}

结果:

【霸道的主线程】执行、x=0
【霸道的主线程】执行、x=1
玩耍的子线程执行、x=0
玩耍的子线程执行、x=1
玩耍的子线程执行、x=2
玩耍的子线程执行、x=3
玩耍的子线程执行、x=4
【霸道的主线程】执行、x=2
【霸道的主线程】执行、x=3
【霸道的主线程】执行、x=4

  在进行线程强制执行的时候一定要获取强制执行线程对象之后才可以执行join()调用。

5. 线程礼让

  线程的礼让指的是先将资源让出去让别的线程先执行。线程的礼让可以使用Thread中提供的方法:

  • 礼让:public static void yield()

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(() -> {
            for (int x = 0; x < 10; x++) {
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "玩耍的子线程");
        Thread threadB = new Thread(() -> {
            for (int x = 0; x < 10; x++) {
                if (x % 3 == 0) {
                    System.out.println("【霸道的线程礼让了!!!】");
                    Thread.yield();
                }
                System.out.println(Thread.currentThread().getName() + "执行、x=" + x);
            }
        }, "霸道的子线程");
        threadA.start();//开始线程
        threadB.start();

    }
}

结果:

【霸道的线程礼让了!!!】
玩耍的子线程执行、x=0
霸道的子线程执行、x=0
玩耍的子线程执行、x=1
霸道的子线程执行、x=1
玩耍的子线程执行、x=2
霸道的子线程执行、x=2
【霸道的线程礼让了!!!】
玩耍的子线程执行、x=3
霸道的子线程执行、x=3
玩耍的子线程执行、x=4
霸道的子线程执行、x=4
玩耍的子线程执行、x=5
霸道的子线程执行、x=5
【霸道的线程礼让了!!!】
玩耍的子线程执行、x=6
霸道的子线程执行、x=6
玩耍的子线程执行、x=7
霸道的子线程执行、x=7
玩耍的子线程执行、x=8
霸道的子线程执行、x=8
【霸道的线程礼让了!!!】
玩耍的子线程执行、x=9
霸道的子线程执行、x=9

  礼让执行的时候每一次调用yield()方法都只会礼让一次当前的资源。.

6. 线程优先级

  从理论上来讲线程的优先级越高越有可能先执行(越有可能先抢占到资源)。在Thread类里面针对于优先级的操作提供有如下的两个处理方法:

  • 设置优先级:public final void setPriority(int newPriority)
  • 获取优先级:public final int getPriority()

  在进行优先级定义的时候都是通过int型的数字来完成的,而对于此数字的选择在Thread类里面就定义有三个常量:

  • 最高优先级:public static final int MAX_PRIORITY --------10
  • 中等优先级:public static final int NORM_PRIORITY --------5
  • 最低优先级:public static final int MIN_PRIORITY ----------1

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Runnable run = () -> {
            for (int x = 0; x < 3; x++) {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread threadA = new Thread(run,"线程A");
        Thread threadB = new Thread(run,"线程B");
        Thread threadC = new Thread(run,"线程C");
        
        //设置线程优先级
        threadA.setPriority(Thread.MIN_PRIORITY);
        threadB.setPriority(Thread.MIN_PRIORITY);
        threadC.setPriority(Thread.MAX_PRIORITY);
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

结果:

线程A
线程C
线程B

线程A
线程C
线程B

线程C
线程A
线程B

  主方法是一个主线程,那么主线程的优先级呢?

代码:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程优先级:"+Thread.currentThread().getPriority());
        Thread threadA = new Thread(()->{},"线程A");
        System.out.println("子线程优先级:"+threadA.getPriority());
    }
}

结果:

主线程优先级:5
子线程优先级:5

  主线程是属于中等优先级,而默认创建的线程也是中等优先级。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 多线程的读者-写者问题是一个经典的同步问题,涉及到多个读线程和写线程对共享数据的访问。以下是一个可能的Java多线程读者-写者问题的实现代码: ```java class ReaderWriter { int readers = 0; int writers = 0; int writeRequests = 0; public synchronized void startRead() throws InterruptedException { while (writers > 0 || writeRequests > 0) { wait(); } readers++; } public synchronized void endRead() { readers--; notifyAll(); } public synchronized void startWrite() throws InterruptedException { writeRequests++; while (readers > 0 || writers > 0) { wait(); } writeRequests--; writers++; } public synchronized void endWrite() { writers--; notifyAll(); } } class Reader implements Runnable { ReaderWriter readerWriter; public Reader(ReaderWriter readerWriter) { this.readerWriter = readerWriter; } public void run() { try { readerWriter.startRead(); // 读取共享数据的操作 Thread.sleep((int) (Math.random() * 1000)); readerWriter.endRead(); } catch (InterruptedException e) { e.printStackTrace(); } } } class Writer implements Runnable { ReaderWriter readerWriter; public Writer(ReaderWriter readerWriter) { this.readerWriter = readerWriter; } public void run() { try { readerWriter.startWrite(); // 写入共享数据的操作 Thread.sleep((int) (Math.random() * 1000)); readerWriter.endWrite(); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String[] args) { ReaderWriter readerWriter = new ReaderWriter(); for (int i = 0; i < 5; i++) { new Thread(new Reader(readerWriter)).start(); } for (int i = 0; i < 5; i++) { new Thread(new Writer(readerWriter)).start(); } } } ``` 在上面的代码,`ReaderWriter`类是一个用于管理读者和写者访问共享数据的同步类。`startRead()`和`endRead()`方法用于读者访问共享数据的开始和结束,`startWrite()`和`endWrite()`方法用于写者访问共享数据的开始和结束。在每个方法使用`synchronized`关键字来保证同一时间只有一个线程可以执行。`notifyAll()`方法用于唤醒其他正在等待的线程。 `Reader`类和`Writer`类分别是读者和写者线程的实现。在`run()`方法,先调用对应的`startRead()`或`startWrite()`方法来获取访问权限,然后执行读取或写入操作,最后调用对应的`endRead()`或`endWrite()`方法来释放访问权限。 在`main()`方法创建了5个读者线程和5个写者线程,并启动它们。 以上代码是一种可能的多线程读者-写者问题的实现,但并不是唯一的解决方案。在实际应用,还需要考虑更多的场景和线程同步的细节,确保共享数据的一致性和线程的安全执行。 ### 回答2: Java多线程读者-写者问题可以通过使用synchronized关键字和wait()、notify()方法来实现。下面是一个简单的示例代码: ``` public class ReaderWriterProblem { private static final int MAX_READERS = 5; private static final int MAX_WRITERS = 2; private static int activeReaders = 0; private static boolean writerActive = false; public static void main(String[] args) { for (int i = 1; i <= MAX_READERS; i++) { new Thread(new Reader(i)).start(); } for (int i = 1; i <= MAX_WRITERS; i++) { new Thread(new Writer(i)).start(); } } static class Reader implements Runnable { private final int readerId; public Reader(int readerId) { this.readerId = readerId; } @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } read(); } } private void read() { synchronized (ReaderWriterProblem.class) { while (writerActive) { // 如果有写者在执行 try { ReaderWriterProblem.class.wait(); // 等待写者完成 } catch (InterruptedException e) { e.printStackTrace(); } } activeReaders++; // 增加活跃读者数量 } // 执行读操作 System.out.println("Reader " + readerId + "正在执行读操作"); synchronized (ReaderWriterProblem.class) { activeReaders--; // 减少活跃读者数量 if (activeReaders == 0) { // 如果没有其他读者 ReaderWriterProblem.class.notifyAll(); // 唤醒所有等待的线程 } } } } static class Writer implements Runnable { private final int writerId; public Writer(int writerId) { this.writerId = writerId; } @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } write(); } } private void write() { synchronized (ReaderWriterProblem.class) { while (activeReaders > 0 || writerActive) { // 如果有读者在执行或者有写者在执行 try { ReaderWriterProblem.class.wait(); // 等待其他线程完成操作 } catch (InterruptedException e) { e.printStackTrace(); } } writerActive = true; } // 执行写操作 System.out.println("Writer " + writerId + "正在执行写操作"); synchronized (ReaderWriterProblem.class) { writerActive = false; ReaderWriterProblem.class.notifyAll(); // 唤醒所有等待的线程 } } } } ``` 在上述代码,我们使用了一个整型变量`activeReaders`来记录当前活跃的读者数量,当读者开始读操作时,会先判断是否有写者在执行,如果有,则等待写者完成;然后增加`activeReaders`;接着执行读操作。读操作完成后,减少`activeReaders`,如果没有其他读者,则调用`notifyAll()`方法唤醒其他等待的线程。写者也类似,当写者开始写操作时,会先判断是否有其他读者或写者在执行,如果有,则等待其他线程完成;然后执行写操作;最后,设置`writerActive`为false,并调用`notifyAll()`方法唤醒其他等待的线程。 这种方式实现的读者-写者问题可以保证同一时间只能有一个写者或多个读者执行操作,从而保证数据的一致性和并发访问的正确性。 ### 回答3: Java多线程读者-写者问题可以通过使用synchronized关键字和wait()、notify()方法实现。 首先,读者-写者问题是指多个读者线程可以同时读取数据,但写者线程只能在没有读者线程时才能写入数据。 下面是使用Java实现的一个基本读者-写者问题的代码示例: ```java public class ReaderWriter { private int readers; private boolean isWriting; public ReaderWriter() { readers = 0; isWriting = false; } public synchronized void startRead() throws InterruptedException { while (isWriting) { wait(); } readers++; } public synchronized void endRead() { readers--; if (readers == 0) { notifyAll(); } } public synchronized void startWrite() throws InterruptedException { while (isWriting || readers > 0) { wait(); } isWriting = true; } public synchronized void endWrite() { isWriting = false; notifyAll(); } } ``` 上面的代码,ReaderWriter类用于管理读者和写者的访问。其,startRead()方法用于读者开始读取数据,endRead()方法用于读者结束读取;startWrite()方法用于写者开始写入数据,endWrite()方法用于写者结束写入。 在startRead()和startWrite()方法,使用synchronized关键字修饰,确保同一时间只能有一个线程访问该方法。在读者读取数据时,如果有写者在写入,则调用wait()方法使读者线程进入等待状态。在写者写入数据时,如果有其他读者在读取,也调用wait()方法使写者线程进入等待状态。 在endRead()和endWrite()方法,对读者和写者的数量进行更新,并使用notifyAll()方法唤醒等待的线程。当所有读者都结束读取时,唤醒可能等待的写者线程;当写者结束写入时,唤醒可能等待的读者线程。 通过以上方法的实现,能够实现读者-写者问题的多线程并发访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值