Java多线程
概述
- 线程由进程创建,一个进程可以包含多个线程
- 线程是独立的执行路径
- 在程序执行时,后台会有多个线程
- 在一个进程中,如果开辟了多个线程,运行由调度器安排,先后顺序不可干预
- 引入并发控制,防止抢夺资源
- 线程调度会有额外开销
Tread继承
比如用java里的Tread来测试一下,run()和start()的区别:
public class test01 extends Thread{
public void run(){
for(int i=1;i<=20;i++)
System.out.println("-"+i+"-");
}
public static void main(String[] args) {
test01 test01 = new test01();
test01.start();
for (int i = 0; i <= 20; i++) {
System.out.println(i);
}
}
}
Runnable接口
启用Thread代理一下这个接口就可以了,我们可以直接去看一下源码,Thread就是套用了Runnable接口,可以理解为一个是直接改写Run函数然后传入值到Thread中,一个是直接改写Thread。
public class test03 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++)
System.out.println("--");
}
public static void main(String[] args) {
test03 test03 = new test03();
Thread thread = new Thread(test03);
thread.start();
for (int i = 0; i <= 20; i++)
System.out.println(i);
}
}
并发问题
来看一个很直接的问题,下面这个代码直接运行的问题是线程同时占用一个进程资源导致资源紊乱:
public class test04 implements Runnable{
private int num = 10;
@Override
public void run() {
while(true) {
if(num<=0) break;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" get the "+(num--));
}
}
public static void main(String[] args) {
test04 test04 = new test04();
new Thread(test04,"wbw").start();
new Thread(test04,"dyd").start();
new Thread(test04,"cyc").start();
}
}
静态代理
静态代理是利用另一个class的方式来达到代理的效果,thread也是一个静态代理的方式。
public class test06 {
public static void main(String[] args) {
proxy proxy = new proxy(new You());
proxy.happy();
}
}
interface Play{
void happy();
}
class You implements Play{
@Override
public void happy() {
System.out.println("happy!");
}
}
class proxy implements Play{
private Play test;
public proxy(Play test){
this.test=test;
}
@Override
public void happy() {
bef();
this.test.happy();
after();
}
private void after() {
System.out.println("after!");
}
private void bef() {
System.out.println("before!");
}
}
Lambda表达式
表达式:func = a->code,前提是函数是接口(一个函数接口)。
public class test08 {
static class Like2 implements Ilike{
@Override
public void print() {
System.out.println("i like 2");
}
}
public static void main(String[] args) {
Ilike like = new Like1();
like.print();
like = new Like2();
like.print();
like = ()->{ //lambda表达式
System.out.println("i like 3");
};
like.print();
}
}
//接口
interface Ilike{
void print();
}
//实现类
class Like1 implements Ilike{
@Override
public void print() {
System.out.println("i like 1");
}
}
线程停止
在Thread中我们可以设置sleep(睡眠),yield(礼让)来操纵线程的执行方式。
class MyYield implements Runnable{
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} //线程睡眠
System.out.println(Thread.currentThread().getName()+"hello!");
Thread.yield(); //线程礼让看CPU调度
System.out.println(Thread.currentThread().getName()+"bye!");
}
}
线程优先级
设置线程的优先级并且获取优先级。
priority priority = new priority();
Thread t1 = new Thread(priority);
Thread t2 = new Thread(priority);
Thread t3 = new Thread(priority);
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);
t3.start();
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
守护线程
在虚拟机中可以设置守护线程来操作一些日志,内存之类任务。虚拟机必须确保用户进程结束,但不保证守护线程结束。
t1.setDaemon(true); //true为守护线程
线程同步机制
线程同步有锁机制,共享一块空间,因此访问时加入了锁机制。我们引入synchronized去实现锁的功能,只需对可修改对象加锁即可。以下为两种形式的上锁。
private synchronized void cla(){}
synchronized (class_name){
}
lock锁
class A{
private final ReentrantLock lock = new ReentrantLock();
public void func(){
try{
lock.lock();
......
}
finally {
lock.unlock();
}
}
}
死锁
产生死锁的条件:
1.互斥条件:一个资源只能被一个进程使用
2.请求与保持条件:一个进程因请求资源而阻塞时,对已有资源保持不放
3.不剥夺条件:进程已获得的资源,在未使用完前,不能剥夺
4.循环等待条件:若干进程间形成循环等待关系
线程通信
管程法用于通信,可以用生产者消费者问题来实现,当数据缓冲区满时生产者需要等待消费者使用,并且让出锁;反之等待生产者生产,如下面的例子使各个线程互相通信不干扰。还有一个信号灯法就是设立一个flag来判断是否wait。
package com.dyd.thread;
public class test17 {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
class Productor extends Thread{
SynContainer container;
public Productor(SynContainer container){
this.container=container;
}
public void run(){
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("produce "+i);
}
}
}
class Consumer extends Thread{
SynContainer container;
public Consumer(SynContainer container){
this.container=container;
}
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("buy "+container.pop().id);
}
}
}
class Chicken{
int id;
public Chicken(int id){
this.id=id;
}
}
class SynContainer{
Chicken[] chickens = new Chicken[10];
int cnt = 0;
public synchronized void push(Chicken chicken){
if(cnt== chickens.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chickens[cnt] = chicken;
cnt++;
this.notifyAll();
}
public synchronized Chicken pop(){
if(cnt==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cnt--;
Chicken chicken = chickens[cnt];
this.notifyAll();
return chicken;
}
}
线程池
开辟一个线程池来装载线程满足使用,用execute来启动线程shutdown关闭线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class test18 {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new myThread());
service.execute(new myThread());
service.execute(new myThread());
service.shutdown();
}
}
class myThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}