Java多线程

一:Java中三种多线程的实现方式

在Java中实现多线程有两种途径,

  • 继承Thread类,重写run方法,多线程启动的方法,就是start方法。(单继承的局限)
public class TestThread extends Thread {
    private String name;

    public TestThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(this.name + "-->" + i);
        }
    }

    public static void main(String[] args) {
        TestThread thread1 = new TestThread("线程1");
        TestThread thread2 = new TestThread("线程2");
        TestThread thread3 = new TestThread("线程3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  • 实现Runnable接口,并且重写run方法。多线程的启动还是Thread的start方法。
public class TestRunnable implements Runnable {
    private String name;

    public TestRunnable(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println(this.name + "-->" + i);
        }
    }

    public static void main(String[] args) {
        TestRunnable thread1 = new TestRunnable("线程1");
        TestRunnable thread2 = new TestRunnable("线程2");
        TestRunnable thread3 = new TestRunnable("线程3");
        new Thread(thread1).start();
        new Thread(thread2).start();
        new Thread(thread3).start();
    }
}

两种方式的区别:

  • 实现Runnable接口解决了单继承的局限,Thread类实现了Runable接口
  • 线程资源共享,Runnable更好的诠释了数据共享,多线程访问同一资源
    public static void main(String[] args) {
        TestRunnable thread1 = new TestRunnable("线程1");
        new Thread(thread1).start();
        new Thread(thread1).start();
        new Thread(thread1).start();
    }

jdk1.5的新特性,线程执行完接收返回值,也是线程实现的第三种方式,

package com.java.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class TestCallable implements Callable<String> {
    private int ticket = 10;

    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) {
                System.out.println("卖票,票数=" + ticket--);
            }
        }
        return "票卖完了";
    }

    public static void main(String[] args) throws Exception {
        TestCallable testCallable1 = new TestCallable();
        TestCallable testCallable2 = new TestCallable();
        FutureTask<String> futureTask1 = new FutureTask<>(testCallable1);
        FutureTask<String> futureTask2 = new FutureTask<>(testCallable2);
        new Thread(futureTask1).start();
        new Thread(futureTask2).start();
        System.out.println("futureTask1 = " + futureTask1.get());
        System.out.println("futureTask2 = " + futureTask2.get());
    }
}

二:线程的命名与取得,Thread.currentThread().getName(),线程能够自动命名

public class TestRunnable implements Runnable {
    private String name;

    public TestRunnable(String name) {
        this.name = name;
    }

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

    public static void main(String[] args) {
        TestRunnable thread1 = new TestRunnable("线程1");
        new Thread(thread1,"线程1").start();
        new Thread(thread1).start();
        new Thread(thread1,"线程3").start();
    }
}

每一个JVM启动,至少启动两个线程

  • main线程,以及程序的子线程
  • gc线程,负责垃圾回收

三:线程的休眠

  •   Thread.sleep(1000); 有先后差别

四:线程的优先级Thread类里面提供的两个方法,以及三个常量

    public static void main(String[] args) {
        TestThread thread1 = new TestThread("线程1");
        TestThread thread2 = new TestThread("线程2");
        TestThread thread3 = new TestThread("线程3");
        thread1.setPriority(MAX_PRIORITY);
        thread2.setPriority(MIN_PRIORITY);
        thread3.setPriority(NORM_PRIORITY);
        thread1.start();
        thread2.start();
        thread3.start();
    }

五:总结

  • 主线程属于中等优先级,
  • Thread.currentThread()可以获取当前线程的对象。

六:同步问题

多个线程访问同一个资源需要考虑的问题,4个人卖5张票,在判断和修改是分开执行的,最后一张票出现了资源的延迟,

 

如何解决同步的问题

当有线程在执行的时候,其他的线程先等待。在Java中要想实现线程的同步需要使用synchronized关键字。

使用方式,

  • 同步代码块
  • 同步方法

Java中有四种代码块,普通代码块,构造块,静态块,同步块。

  • 以下是同步代码块,

  • 以下是同步方法,
public class TestSynchronized implements Runnable {
    private int ticket = 50;

    @Override
    public void run() {
        try {
            for (int i = 0; i < 200; i++) {
                //卖票的过程
                if (sell()) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public synchronized boolean sell() throws InterruptedException {
        if (ticket > 0) {
//            Thread.sleep(200);
            System.out.println(Thread.currentThread().getName() + "...票数=" + this.ticket--);
            return false;
        } else {
            return true;
        }
    }

    public static void main(String[] args) {
        TestSynchronized thread0 = new TestSynchronized();
        new Thread(thread0,"票贩子A").start();
        new Thread(thread0,"票贩子B").start();
        new Thread(thread0,"票贩子C").start();
        new Thread(thread0,"票贩子D").start();
    }
}

死锁:是一个线程对象等待另一个线程对象执行完毕后的操作结果,同步过多可能发生死锁。

多个线程访问一个资源需要考虑哪些问题,

  • 同步问题,可以使用同步代码块,也可以使用同步方法
  • 过多的使用同步可能造成死锁

七:生产者和消费者

  • 生产者负责生产数据,消费者负责取走数据
  • 生产者每生产一组数据,消费者就取走一组数据

等待与唤醒,

  • super.wait();
  • super.notify();

sleep和wait得区别,

  • sleep是Thread类的方法,wait是Object类的方法
  • sleep可以设置休眠时间,时间一到自动唤醒,而wait需要notify去唤醒。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章