Java线程

java

Java线程启动方式

在Java中有两种方式可以启动线程,一种方式是通过继承Thread类,另一种方式通过继承Runnable接口。

public class MyThread extends Thread {

@Override

public void run() {

// TODO Auto-generated method stub

for(int i = 0; i < 10; ++i) {

System.out.println(i);

}

}

public static void main(String []args) {

MyThread thread = new MyThread();

/**线程的启动的通过调用start方法,直接调用run方法无异于调用类中的方法*/

thread.start();

}

}

public class MyRunnable implements Runnable {

@Override

public void run() {

// TODO Auto-generated method stub

for(int i = 0 ; i < 10; ++i) {

System.out.println(i);

}

}

public static void main(String []args) {

MyRunnable task = new MyRunnable();

Thread thread = new Thread(task);

thread.start();

}

}

 

创建出Thread类的对象之后通过调用start方法启动线程的运行,而不是run方法。当线程的代码逻辑执行完毕之后,线程会自动结束(就是说当程序执行完run方法体后,线程结束)。值得注意的是,对Java来说,run方法没有任何特别之处,像main方法一样,它只是新线程知道调用的方法名称。因此,在Runnable上或者Thread上调用run方法是合法的,但这并不启动新的线程。

Java线程的同步机制

在Java虚拟机中,每个类和对象在逻辑上都有一个与之关联的监视器,该监视器便是获取类和对象的锁,在任何时候只允许一个线程拥有类和对象的锁。

类锁实际上也是通过对象锁(Class对象)来实现的,当虚拟机加载一个class文件时,会创建一个java.lang.Class类的实例,当锁住类时,实质上是锁住的该类对应的Class对象。

线程可以对同一个对象上锁,对于每一个对象,Java虚拟机维护一个加锁计数器,线程每次获得该对象锁时,计数器就加一,释放锁时,计数器就减一,只有当计数器为零时,锁就被完全释放。

public class NumberTask implements Runnable {

public String num;

public Demo main;

public NumberTask(String num, Demo main) {

this.num = num;

this.main = main;

}

@Override

public void run() {

try {

main.run(num);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public class Demo {

public void run(String threadNum) throws InterruptedException {

for (int i = 0; i < 5; i++) {

System.out.println("[" + threadNum + "] " + i);

}

}

public static void main(String []args) {

Demo ma = new Demo();

ExecutorService es = Executors.newFixedThreadPool(2);

for (int i = 0; i < 2; i++) {

String num = "THREAD_" + String.format("%02d", i+1);

es.submit(new NumberTask(num, ma));

}

}

}

在上述代码中,NumberTask中run方法调用Demo类中run,run方法没有添加synchronized关键字,也就是允许多个线程进入该方法,因此输出结果如下:

[THREAD_01] 0

[THREAD_01] 1

[THREAD_01] 2

[THREAD_02] 0

[THREAD_02] 1

[THREAD_02] 2

[THREAD_02] 3

[THREAD_01] 3

[THREAD_02] 4

[THREAD_01] 4

Java中synchronized关键字,用来控制线程之间同步的,如果在Demo类中的run方法添加synchronized关键字,则只是允许一个线程访问该方法,因此结果输出如下:

[THREAD_01] 0

[THREAD_01] 1

[THREAD_01] 2

[THREAD_01] 3

[THREAD_01] 4

[THREAD_02] 0

[THREAD_02] 1

[THREAD_02] 2

[THREAD_02] 3

[THREAD_02] 4

使用关键词synchronized主要用来实现线程之间的互斥,即同一时刻只有一个线程允许执行特定的代码。通过互斥的方法来保证多个线程访问共享变量时的正确性。除了互斥访问之外,线程之间也需要通过协作的方式来完成某些任务。此时可以使用Object类提供的wait、notify和notifyAll方法。

public class Cache {

private static final Integer SIZE = 10;

private static List<Integer> caches = new ArrayList<Integer>();

private static int index = 0;

public static void putDate(Integer integer) throws InterruptedException {

synchronized (caches) {

if (caches.size() > SIZE) { // 缓冲区尺寸大于10,线程等待

caches.wait(); // 释放caches对象锁

}

caches.add(index++,integer);

System.out.println("[" + Thread.currentThread().getName() + "]生成数据"

+ integer);

caches.notify(); // 唤醒等待线程

}

}

public static void getDate() throws InterruptedException {

synchronized (caches) {

if (caches.size() <= 0) {

caches.wait(); // 释放caches对象锁

}

System.out.println("[" + Thread.currentThread().getName() +

"]获取数据" + caches.remove(--index));

caches.notify();

}

}

}

public class DateMakeThread extends Thread {

public DateMakeThread(String name) {

super(name);

}

@Override

public void run() {

while(true) {

try {

Cache.getDate();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class DateTakerThread extends Thread {

public DateTakerThread(String name) {

super(name);

}

@Override

public void run() {

Random random = new Random();

for (int i = 0; i < 10; i++) {

try {

Cache.putDate(random.nextInt(100));

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class Main {

public static void main(String []args) {

DateMakeThread dmt = new DateMakeThread("PRODUCER");

dmt.start();

DateTakerThread dtt = new DateTakerThread("CONSUMER");

dtt.start();

}

}

在上述代码,Cache中"生产者-消费者"的缓冲区,DateMakeThread生成数据存入Cache中,Cache类中caches对象是互斥访问的,DateTakerThread用来在Cache中获取数据,值得注意的是:wait,notify,notifyAll方法的使用的前提是获得对象锁,wait方法会使得已获取的对象锁的线程,放弃对象锁。

以上是 Java线程 的全部内容, 来源链接: utcz.com/z/393487.html

回到顶部