JAVA创建线程的两种方法

Java创建线程的方法有两种

两种方法分别是继承Thread类和实现Runnable接口。

  1. 继承Thread类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
  1. 实现Runnable接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
}

public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

两者区别在于,通过继承Thread类,可以重写Thread类中的run()方法,直接调用start()方法启动线程;而通过实现Runnable接口,需要先创建一个实现了Runnable接口的类的实例对象,在创建Thread对象时将该实例对象作为参数传入,并且该实现类必须实现run()方法。由于Java只支持单继承,因此如果已经继承了其他类,则无法使用第一种方法创建线程。

Java引入线程组

为了更好地管理和控制线程。通过将线程分组,可以更轻松地对线程进行统一管理和控制,例如一次性停止所有属于同一线程组的线程等。此外,在开发中,有时需要创建大量的线程,而这些线程可能是相关的,因此通过将它们放入同一个线程组中,可以更清晰地表达它们之间的关系。最后,线程组还可以用于安全管理,因为可以为不同的线程组设置不同的安全策略,以确保线程安全执行。
下面是一个简单的JAVA线程组应用示例:

public class ThreadGroupDemo {
    
    public static void main(String[] args) {
        ThreadGroup group = new ThreadGroup("testGroup"); // 创建一个名为testGroup的线程组
        
        Thread t1 = new Thread(group, new MyRunnable(), "t1");
        Thread t2 = new Thread(group, new MyRunnable(), "t2");
        Thread t3 = new Thread(group, new MyRunnable(), "t3");
        
        t1.start();
        t2.start();
        t3.start();
        
        System.out.println("Active threads in thread group: " + group.activeCount());
        group.list();
    }
    
    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " is running.");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个示例中,我们创建了一个名为“testGroup”的线程组,并向其中添加了三个线程。通过调用activeCount()方法,可以获取线程组当前活动的线程数量。通过调用list()方法,可以输出线程组中所有线程的相关信息。

输出结果如下:

t1 is running.
t3 is running.
t2 is running.
Active threads in thread group: 3
java.lang.ThreadGroup[name=testGroup,maxpri=10]
    Thread[t1,5,testGroup]
    Thread[t3,5,testGroup]
    Thread[t2,5,testGroup]

可以看到,我们创建的线程组包含了三个线程,它们都在运行中。通过list()方法,我们可以查看线程组中包含了哪些线程,并了解每个线程的相关信息。

需要注意的是,线程组并不会影响线程本身的执行,它只是一个逻辑上的分组并提供一些管理和控制的功能。

线程调度和控制

Java中线程控制的几个方法包括:

  1. start()方法:启动一个线程,该方法将在新的线程中调用run()方法。

  2. run()方法:线程执行的代码放在该方法中。

  3. join()方法:主线程等待该方法所属的线程执行完毕后才会继续执行。

  4. sleep()方法:让当前线程休眠一定时间,可以指定时间长度或者时间点。

  5. yield()方法:暂停当前线程的执行,让其他线程有机会运行,但是不会释放锁。

  6. interrupt()方法:中断线程的执行,可以通过isInterrupted()方法来判断线程是否被中断;同时也可以使用Thread.interrupted()方法来清除线程中断状态。

  7. wait()、notify()和notifyAll()方法:用于多线程之间的协作。wait()方法使得当前线程等待另一个线程的信号,而notify()和notifyAll()方法则可以唤醒一个或多个等待的线程。

sleep()和join()方法都可以用于控制线程的执行,
sleep()方法用于暂停当前线程,在给定的时间内不参与CPU时间片调度;
而join()方法则是等待指定线程结束,直到它退出并释放锁,才会让当前线程继续执行。
以下是一个简单的Java程序,展示了如何使用sleep()和join()方法来控制线程的执行顺序和等待时间,演示了sleep()和join()方法的使用:

public class SleepAndJoinExample implements Runnable {
    
    public void run() {
        try {
            // 线程休眠5秒
            System.out.println(Thread.currentThread().getName() + " is sleeping for 5 seconds...");
            Thread.sleep(5000);
            System.out.println(Thread.currentThread().getName() + " has woken up!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new SleepAndJoinExample(), "Thread 1");
        Thread t2 = new Thread(new SleepAndJoinExample(), "Thread 2");
        Thread t3 = new Thread(new SleepAndJoinExample(), "Thread 3");

        // 线程t1启动并等待
        t1.start();
        t1.join();

        // 线程t2启动并等待
        t2.start();
        t2.join();

        // 线程t3启动并等待
        t3.start();
        t3.join();

        System.out.println("All threads have completed.");
    }
}

这个例子创建了三个线程并分别启动它们。然后,每个线程都调用了sleep()方法来模拟执行一些耗时操作。同时,每个线程也调用了join()方法,以确保前一个线程结束后再启动下一个线程。

输出结果应该类似于:

Thread 1 is sleeping for 5 seconds...
Thread 1 has woken up!
Thread 2 is sleeping for 5 seconds...
Thread 2 has woken up!
Thread 3 is sleeping for 5 seconds...
Thread 3 has woken up!
All threads have completed.

wait() 与notify()

在Java中,可以使用notify()方法来激活处于wait状态的线程。notify()方法会随机唤醒一个等待该对象锁的线程。如果想唤醒所有等待该对象锁的线程,可以使用notifyAll()方法。

以下是一个简单的示例代码:

public class WaitNotifyExample {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread 1 is waiting...");
                    lock.wait();
                    System.out.println("Thread 1 is awake!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread 2 is sleeping...");
                    Thread.sleep(2000);
                    System.out.println("Thread 2 is notifying...");
                    lock.notifyAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("All threads completed.");
    }
}

在这个例子中,我们创建了两个线程:thread1和thread2。thread1进入了synchronized代码块并调用wait()方法进入等待状态,直到被thread2通过notifyAll()方法唤醒。
当thread2执行完任务后,它会调用notifyAll()方法唤醒所有等待该对象锁的线程(在本例中只有一个线程在等待)。

调用yield()方法

定义了YieldDemo类作为Thread的子类,覆盖了其run()方法。在run()方法中,我们使用for循环打印出当前线程的名称和计数器的值,并调用Thread.yield()方法。此方法会暂停当前正在执行的线程并允许其他线程运行。

在main()方法中,我们创建和启动三个YieldDemo线程。当这些线程运行时,它们会交替运行,并在每次迭代时调用yield()方法,从而给其他正在运行的线程机会运行。
下面是一个简单的Java yield()示例:

public class YieldDemo extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " running " + i);
            Thread.yield();
        }
    }

    public static void main(String[] args) {
        YieldDemo t1 = new YieldDemo();
        YieldDemo t2 = new YieldDemo();
        YieldDemo t3 = new YieldDemo();

        t1.start();
        t2.start();
        t3.start();
    }
}

interrupt()中断Java线程

下面是一个简单的示例,演示如何使用interrupt()中断Java线程:

public class MyThread extends Thread {
    public void run() {
        try {
            System.out.println("Starting my thread...");
            // 让线程睡眠5秒钟
            Thread.sleep(5000);
            System.out.println("My thread is running...");
        } catch (InterruptedException e) {
            System.out.println("My thread was interrupted!");
            return;
        }
        System.out.println("My thread is done.");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        // 让主线程睡眠1秒钟
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断myThread线程
        myThread.interrupt();
    }
}

代码中创建了一个名为MyThread的线程类,并在其中实现了run()方法。这个方法会启动线程并将线程睡眠5秒钟,然后输出一条消息。如果线程被中断,则会捕获InterruptedException异常并退出方法。

Main类中,我们创建了MyThread实例,并启动线程。随后,我们让主线程睡眠1秒钟,并在之后调用myThread.interrupt()方法中断线程。该方法将触发MyThread实例中的InterruptedException异常,从而停止线程的执行。

执行上述代码后,你会看到输出如下的结果:

Starting my thread...
My thread was interrupted!

当我们调用myThread.interrupt()方法时,线程被中断了,并且在run()方法中捕获到了InterruptedException异常。

使用wait()notify()notifyAll()方法

Java多线程编程中重要的机制,它们可以协调线程之间的操作。下面是一些场景的示例:

  1. 生产者-消费者模式:当生产者线程生产出一个对象后,它会将其放入一个共享的缓冲区,同时唤醒等待中的消费者线程。如果缓冲区已满,则生产者线程会等待,直到有消费者取走了一个对象才会被唤醒。
public class ProducerConsumer {
  private List<Integer> buffer = new ArrayList<>();
  private int capacity = 5;

  public void produce() throws InterruptedException {
    synchronized (this) {
      while (buffer.size() == capacity) {
        System.out.println("Buffer is full. Waiting for consumer to consume from buffer..");
        wait();
      }

      int item = new Random().nextInt(100);
      buffer.add(item);
      System.out.println("Produced: " + item);
      notify(); // notifies any waiting consumer threads
    }
  }

  public void consume() throws InterruptedException {
    synchronized (this) {
      while (buffer.size() == 0) {
        System.out.println("Buffer is empty. Waiting for producer to produce into buffer..");
        wait();
      }

      int item = buffer.remove(0);
      System.out.println("Consumed: " + item);
      notify(); // notifies any waiting producer threads
    }
  }
}
  1. 协调线程执行顺序:例如,我们希望一个线程在另一个线程完成后才能执行,可以使用wait()notify()方法来实现。
public class SequentialExecution {
  private boolean isCompleted = false;

  public synchronized void waitToComplete() throws InterruptedException {
    while (!isCompleted) {
      wait();
    }
  }

  public synchronized void markAsCompleted() {
    isCompleted = true;
    notify();
  }
}

在这个例子中,一个线程可以调用waitToComplete()方法来等待另一个线程完成工作。一旦另一个线程调用了markAsCompleted()方法,第一个线程就会被唤醒。

  1. 线程间通信:例如,我们希望两个线程之间交替打印数字,可以使用wait()notify()和标志位来实现。
public class AlternatePrinting {
  private int maxNumber = 10;
  private int currentNumber = 1;
  private boolean isOdd = true;

  public synchronized void printOdd() throws InterruptedException {
    while (currentNumber <= maxNumber) {
      if (!isOdd) {
        wait();
      }

      System.out.println(Thread.currentThread().getName() + ": " + currentNumber);
      currentNumber++;
      isOdd = false;
      notifyAll();
    }
  }

  public synchronized void printEven() throws InterruptedException {
    while (currentNumber <= maxNumber) {
      if (isOdd) {
        wait();
      }

      System.out.println(Thread.currentThread().getName() + ": " + currentNumber);
      currentNumber++;
      isOdd = true;
      notifyAll();
    }
  }
}

在这个例子中,我们创建了一个AlternatePrinting类,其中包含了printOdd()printEven()方法,这两个方法分别负责奇数和偶数的打印。我们使用一个属性isOdd来记录当前应该打印奇数还是偶数,如果该属性为true,则说明应该打印奇数,否则应该打印偶数。在每个方法内部,我们使用wait()方法来使线程等待,直到另一个线程打印完数字并唤醒了该线程。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值