Java多线程小结

程序 = 算法 + 数据结构。程序是为了完成某种特定任务,用编程语言写的一组指令集合
进程:正在运行的一个程序
线程:进程内部的一条一条的执行路径,之前写的代码都是单线程的

多线程优点

增加用户的操作体验(你在看视频的同时可以听到声音)
提高cpu利用率

1.通过thread类创建

1.创建一个继承thread的子类
2.重写run方法,代码块为要执行的东西
3.创建对象
4.调用这个对象的start方法(从thread继承过来的)

//生成100以内的偶数
public class play{
	public static void main(String[] args) {
		mytest my = new mytest();
		my.start();
	}
}

class mytest extends Thread{
	public void run() {
		for(int i=0;i<100;i++)
			if(i%2==0)
				System.out.println(i);
	}
}
*********************************************************************
常用方法:
start():启动线程,调用run方法。
run():需要重写

currentThread():静态方法,建议用Thread.调用,返回结果为当前线程
getName():获得当前线程的名字
setName():设置名字(默认名字为Thread-n),也可以才niu对象的时候用构造函数设置线程名字
isAlive():判断线程是否还活着。

yield():静态方法,暂停当前线程(释放CPU控制权),但是不阻塞,紧接着下一时间短这个线程还有可能抢到CPU控制权。也是直接在run内调用即可
join():阻塞线程(插队)。比如说在主线程内调用a.join(),那么主线程就阻塞了,直到a线程运行结束后主线程才继续开始。在司机与售票员那个问题中可以用。会抛出InterruptedException异常,需要接收一下
sleep(long time):静态方法,设置当前线程的休眠时间,单位为毫秒(千分之一秒)。会抛出InterruptedException异常,需要接收一下。直接在run方法内设置即可,如sleep(10);

设置线程的优先级:
三个常量,可以直接调用
MAX_PRIORITY:10
MIN_PRIORITY:10
NORM_PRIORITY:10

getPriority():获得优先级
setPriority(int x):设置优先级,范围为1~10,默认为5
---------------------------------------------------------------------------
stop():强制结束线程,杀死线程。(过时了,不再用了,只需要认识就好)

2.通过Runnable接口创建

1.创建一个继承Runnable的子类
2.重写run方法,代码块为要执行的东西
3.创建对象
4.将这个对象传递到Thread的构造器中,创建Thread对象
5.调用Thread对象的start方法

因为没有继承Thread类,所以说调用Thread类的时候需要用Thread.调用
public class play{
	public static void main(String[] args) {
		test te = new test();
		Thread th = new Thread(te);
		th.start();
	}
}

class test implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<100;i++)
			if(i%2==0)
				System.out.println(i);
	}
}

Thread与Runnable差别
1.一般来说使用Runnable,因为一个类只能继承一个父类,但是能继承多个接口。
2.Rannable进行线程之间共享数据比较简单,不用设置为static了。
3.Thread内部源码也继承了Runnable。

3.线程的生命周期

新建 (new出来对象),
就绪 (调用statr,等待进入CPU),
运行 (进入cpu),
阻塞 (等待IO操作),
死亡 (程序运行结束)。

4.临界资源,临界区

synchronized        加锁,设置临界区

1.synchronized(this) {处理临界资源语句,代码块}       
小括号里面是锁(可以写任意对象),但是线程要共用一个锁,所以说小括号内的对象要一致,一般用this,因为this指的是同一个对象
这样只适用于继承Runnable的对象,不适合thread,应为this指的不是同一个对象

2.当方法修饰符,来修饰一个方法,只有当这个方法内全是和临界资源有关的才行
Runnable: private synchronized void show(){同步代码块} 然后可以用run调用这个,会有一个默认的this
Thread:只能同时也把这个类设置成静态的,因为this指的是不同对象

3.使用Look锁,look是一个接口,用的是里面的ReentrantLock,锁的也是当前对象,在继承Thread类内使用的话,也需要设置成静态的,避免look指向不同的对象
import java.util.concurrent.locks.ReentrantLock;

public class play{
	public static void main(String[] args) {
		train ta =new train();
		
		Thread th = new Thread(ta,"线程一");
		Thread th1 = new Thread(ta,"线程二");
		th.start();
		th1.start();
	}
}
class train implements Runnable{
	private int tick = 200;
	private ReentrantLock look = new ReentrantLock();
	public void run() {
		while(true) {
			try {
				look.lock();		上锁
				if(tick>0) {
					System.out.println(Thread.currentThread().getName()+"票号为"+tick);
					tick--;
				}
				else
					break;
			}
			finally {
				look.unlock();		写在finally语句内,无论如何都会解锁
			}
		}
	}
}



Look与synchronized的差别:
1.look是手动上锁,手动解锁,synchronized是自动上锁解锁

5.死锁

临界区,临界资源应尽量少用,避免死锁

6.线程通信

只能在同步代码块内用,Look内用不成。
调用这三个方法的对象,必须是当作锁的那个对象,换成别的会报错。this的话可以不写
	wait()		阻塞当前进程,并且释放手中的锁。也会报出InterruptedException异常,需要接收
	notify()		唤醒之前在这个代码快内阻塞的进程,优先唤醒优先级高的,只唤醒一个
	notifyAll()		唤醒所有阻塞的进程,优先级高的先被唤醒并执行,唤醒多个

三个方法是在object类内定义的

wait与sleep的异同:
	同:都可以阻塞进程。
	异:sleep在哪都可以用,wait只能在同步代码块内用
		sleep不会释放锁,wait会


7.使用Callable接口创建

这里需要重写call方法,有返回值,可以抛异常,支持泛型

1.创建一个实现Callable的实现类(需要导入)
2.实现call方法
3.在主线程中创建这个类的对象
4.将创建的这个对象传递到FutureTask构造器中(需要导入)
5.创建Thread对象,调用start方法
6.利用新建的FutureTask对象,可以获得返回值

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

public class play{
	public static void main(String[] args) {
		test te = new test();
		
		FutureTask fu = new FutureTask(te);
		
		new Thread(fu).start();
		
		try {
			Object oj = fu.get();		//获取call方法的返回值
			System.out.println(oj);
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
}

class test implements Callable{
	
	@Override
	public Object call() throws Exception {
		int sum=0;
		for(int i=0;i<=100;i++)
			if(i%2==0) {
				System.out.println(i);
				sum += i;
				}
		return sum;
	}
	
}

8.使用线程池创建

Executors

好处:
1.减少了创建新线程的时间
2.降低资源消耗
3.便于线程管理

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class play{
	public static void main(String[] args) {
		ExecutorService st = Executors.newFixedThreadPool(10);
		
		st.execute(new test());			适用于Runnable对象
		//st.submit(task)				适用于Callable对象,有返回值,接收方法和前面一样
		st.shutdown();					关闭线程池
	}
}


class test implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<100;i++)
			if(i%2==0)
				System.out.println(i);
	}
}



生产者消费者代码
写的不好,别打我

public class play{
	public static void main(String[] args) {
		clerk cl = new clerk();
		productor pd = new productor(cl);
		customer cu = new customer(cl);
		Thread th1 = new Thread(pd , "生产者");
		Thread th2 = new Thread(cu , "消费者");
		th1.start();
		th2.start();
	}
}

class clerk{
	private int num = 20;
	public void setNum(int num) {
		this.num = num;
	}
	
	public int getNum() {
		return num;
	}

}

class productor implements Runnable{
	private clerk ple;
	public productor(clerk ple) {
		this.ple = ple;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(ple) {
				System.out.println("开始生产商品.......");
				if(ple.getNum()>0) {
					ple.setNum(ple.getNum()-1);
					System.out.println("剩余商品"+(20-ple.getNum()));
					ple.notify();
				}
				else
					try {
						System.out.println("没有空余位置了,暂停生产");
						ple.wait();
					} 
					catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			}
		}
	}
}
	


class customer implements Runnable{
	private clerk ple;
	public customer(clerk ple) {
		this.ple = ple;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(ple) {
				System.out.println("开始购买商品.......");
				if(ple.getNum()<20) {
					ple.setNum(ple.getNum()+1);
					System.out.println("剩余商品"+(20-ple.getNum()));
					ple.notify();
				}
				else
					try {
						System.out.println("没有产品了,暂停购买");
						ple.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			}
		}
		
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值