首先讲一下Thread的构造器
Thread() : 创建新的 Thread 对象 new 自己创建得继承Thread得类 Thread(String threadname) : 创建线程并指定线程实例名 Thread(Runnable target) : 指定创建线程的目标对象,它实现了 Runnable 接 口中的 run 方法 里面放的是实现Runnable接口的线程类 Thread(Runnable target, String name) : 创建新的 Thread 对象 Thread的方法: void start(): 启动线程,并执行对象的 run() 方法 run(): 线程在被调度时执行的操作 String getName(): 返回线程的名称 void setName(String name) : 设置该线程名称 static Thread currentThread(): 返回当前线程。在 Thread 子类中就是this ,通常用于主线程和 Runnable 实现类 static void yield() : 线程让步 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程 若队列中没有同优先级的线程,忽略此方法 join() : 当某个程序执行流中调用其他线程的 join() 方法时,调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止 低优先级的线程也可以获得执行 static void sleep(long millis) : ( 指定时间 : 毫秒 ) 令当前活动线程在指定时间段内放弃对 CPU 控制 , 使其他线程有机会被执行 , 时间到后重排队。 抛出 InterruptedException 异常 stop(): 强制线程生命期结束,不推荐使用 boolean isAlive() : 返回 boolean ,判断线程是否还活着方式一:继承Thread类
1.继承Thread类 2.重写run方法 3.创建对象 4.调用start方法
//两个线程输出1-100之间奇偶数
//线程一:输出奇数
class MyThread1 extends Thread{ //1.继承Thread
@Override
public void run() { //2.重写run方法
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(i+"线程1");
}
}
}
}
//线程2:输出偶数
class MyThread2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(i+":线程2");
}
}
}
}
//主线程
public class MyThread {
public static void main(String[] args) {
MyThread1 mth1 = new MyThread1(); //3.创建对象
MyThread2 mth2 = new MyThread2();
mth1.start(); //4.调用.start方法
mth2.start();
}
}
方式二:实现Runnable接口
1.实现Runnable接口 2.重写run方法 3.通过Thread类的构造器创建对象 4.将含Runnable接口的对象作为参数传给Thread类构造器中 5.调用Thread类的start方法
//通过Runnable接口实现多线程
class Runnable1 implements Runnable{ //1.实现Runnable接口
private String name;
public Runnable1(String name) {
this.name = name;
}
@Override
public void run() { //2.重写run方法
for (int i = 0; i < 5; i++) {
System.out.println(name +":"+i);
try {
Thread.sleep((int) (Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//main方法
public class MyRunnable{
public static void main(String[] args) {
Runnable1 run1 = new Runnable1("A");
Runnable1 run2 = new Runnable1("B");
Thread aaa =new Thread(run1);
aaa.start();
new Thread(new Runnable1("c")).start();//3.new Thread类构造器 4.含Runnbale接口的对象作为参数传给Thread类构造器 5调用.start方法
}
}
Runnable和Thread实现多线程的区别:
1.Runnable可以实现资源共享,创建一个Runnable接口的对象,这个对象作为一个参数传进Thread类里面两次,创建两个线程,但是两个线程执行的都是同一个任务,而Thread每创建一个类就是一个任务,不能实现资源共享
2.Thread是单继承,有局限性
方式三:实现callable接口
1.创建实现callable接口的实现类
2.重写call方法
3.创建接口实现类的对象
4.对象作为参数传给futuretask可以得到返回值,
5.futuretask作为参数传给线程类,完成线程的创建
public class CallableTest {
public static void main(String[] args) {
//3.创建实现callable接口的实现类的对象
Numbe nn = new Numbe();
//4.将对象作为参数传给FutureTask, FutureTask可以得到callable的返回值
FutureTask futureTask = new FutureTask(nn);
//5.将futureTask对象作为参数传给线程类,实现线程的创建
Thread t = new Thread(futureTask);
t.start();
//利用futureTask得到callable的返回值
try {
Object num = futureTask.get();
System.out.println("总和为:"+num);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//1.创建实现callable接口的实现类
class Numbe implements Callable{
private int num;
//2.重写call方法
@Override
public Object call() throws Exception {
for (int i = 1; i <= 100; i++) {
if(i%2==0) {
System.out.println(i);
num += i;
}
}
return num;
}
}
与使用
Runnable
相比,
Callable
功能更强大些
相比run()方法,可以有返回值
方法可以抛出异常
支持泛型的返回值
需要借助
FutureTask
类,比如获取返回结果
Future
接口
可以对具体
Runnable
、
Callable
任务的执行结果进行取消、查询是否完成、获取结果等。
FutrueTask
是
Futrue
接口的唯一的实现类
FutureTask
同时实现了
Runnable, Future
接口。它既可以作为Runnable被线程执行,又可以作为
Future
得到
Callable
的返回值
方式四:使用线程池、
1.首先创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
2.执行线程
executorService.execute(number1);//execute适用于Runnable接口
executorService.submit();//submit适用于callable接口
3.关闭线程池
executorService.shutdown();
public class ExecutorsTest {
public static void main(String[] args) {
//1。首先创建一个线程池,里面有十个可用线程,ExecutorService是接口继承于Executors是工具类
ExecutorService executorService = Executors.newFixedThreadPool(10);
//ThreadPoolExecutor是ExecutorService的一个子类
ThreadPoolExecutor service = (ThreadPoolExecutor) executorService;
service.setCorePoolSize(15);
service.setMaximumPoolSize(10);
// service.setKeepAliveTime(l);
Number1 number1 =new Number1();
Number2 number2 =new Number2();
//2.执行线程,但是线程执行的方法需要自己写
executorService.execute(number1);//execute适用于Runnable接口
executorService.execute(number2);
// executorService.submit();//submit适用于callable接口
//3.关闭连接池
executorService.shutdown();
}
}
class Number1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class Number2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
背景:
经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:
提前
创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程管理
corePoolSize
:核心池的大小
maximumPoolSize
:最大线程数
keepAliveTime
:线程没有任务时最多保持多长时间后会终止
线程池相关API
JDK 5.0
起提供了线程池相关
API
:
ExecutorService
和
Executors
ExecutorService
:真正的线程池接口。常见子类
ThreadPoolExecutor
void execute(Runnable command)
:执行任务
/
命令,没有返回值,一般用来执行Runnable
2.同步问题
解决同步的方法:
1.同步代码块
synchronized(同步监视器){
需要被同步的代码
}
//例子:创建个窗口卖票,总票数为100张.使用实现Runnable接口的方式
//main方法
public class SaleTicket {
public static void main(String[] args) {
Ticket t1 = new Ticket();
Thread thr1 =new Thread(t1);
Thread thr2 = new Thread(t1);
thr1.setName("A");
thr2.setName("B");
thr1.start();
thr2.start();
}
}
class Ticket implements Runnable{
private static int TICKET_NUM =100;//总票数为100
@Override
public void run() {
while (true){
synchronized (this){//如果是继承的话,就不能用this,需要用Ticket.class
if (TICKET_NUM>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"窗口:售票,票号为"+TICKET_NUM);
TICKET_NUM--;
}
else {
break;
}
}
}
}
}
2.同步方法
public synchronized void 同步方法(){
需要被同步的代码
}
//例子:创建个窗口卖票,总票数为100张.使用实现Runnable接口的方式
//main方法
public class SaleTicket {
public static void main(String[] args) {
Ticket t1 = new Ticket();
Thread thr1 =new Thread(t1);
Thread thr2 = new Thread(t1);
thr1.setName("A");
thr2.setName("B");
thr1.start();
thr2.start();
}
}
class Ticket implements Runnable{
private static int TICKET_NUM =100;//总票数为100
@Override
public void run() {
while (true){
show();//同步方法
}
}
//同步方法
public synchronized void show(){//这是接口实现同步的方法,如果是继承的话,需要static静态的
if (TICKET_NUM>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"窗口:售票,票号为"+TICKET_NUM);
TICKET_NUM--;
}
}
}
3.lock锁
1.创建锁 ReentrantLock lock = new ReentrantLock()
try{
2.使用锁 lock.lock()
}finally{
3.解锁 lock.unlock()
}
//例子:创建个窗口卖票,总票数为100张.使用实现Runnable接口的方式
//main方法
public class SaleTicket {
public static void main(String[] args) {
Ticket t1 = new Ticket();
Thread thr1 =new Thread(t1);
Thread thr2 = new Thread(t1);
thr1.setName("A");
thr2.setName("B");
thr1.start();
thr2.start();
}
}
class Ticket implements Runnable{
private static int TICKET_NUM =100;//总票数为100
private ReentrantLock lock = new ReentrantLock(); //创建lock锁
@Override
public void run() {
while (true){
try{
lock.lock(); //使用lock锁方法
if (TICKET_NUM>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"窗口:售票,票号为"+TICKET_NUM);
TICKET_NUM--;
}else{
break;
}
}finally{
lock.unlock(); //解锁
}
}
}
}
3.线程通信
wait() 阻塞当前线程,并释放锁
notify()唤醒一个阻塞的线程
notifyall()唤醒所有阻塞的线程
以上三个方法的调用者必须是 同步监视器
//使用两个线程打印 1-100。线程1, 线程2 交替打印
public class CommunicationTest {
public static void main(String[] args) {
Number nb = new Number();
Thread t1 = new Thread(nb);
Thread t2 =new Thread(nb);
t1.setName("线程A");
t2.setName("线程B");
t1.start();
t2.start();
}
}
class Number implements Runnable{
private int num =1;
@Override
public void run() {
while (true){
synchronized (this){
notify();//没有阻塞的线程拿到锁之后,唤醒阻塞的线程
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=100){
System.out.println(Thread.currentThread().getName()+":"+num);
num++;
try {
wait();//打印完了,当前线程阻塞,并释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}



