Java教程

[Java 多线程 01] 初级多线程 2011.11.13!!!

本文主要是介绍[Java 多线程 01] 初级多线程 2011.11.13!!!,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java多线程


一个程序运行有一个进程,进程里有多个线程:main函数,JC(垃圾回收线程)。

1. 线程创建

1. 继承Thread类(Thread类也继承了Runnable接口)

使用:

//1. 自定义类继承Thread类
//2. 重写run()方法
//3. .start()开始运行线程(调用run()则不是多线程,是顺序运行)

2. 实现Runnable接口

因为Java单继承的原因,接口方便同一个对象被多个线程使用

使用:

//1. 定义MyRun实现Runnable接口(重写run()方法)
MyRun implements Runnable{}
//2. 创建实现类对象
MyRun myRun = new MyRun();
//3. 创建代理类对象,并启动
new Thread(myRun()).start();
//or
Thread thread = new Thread(myRun);//代理
thread.start();

3. 实现Callable接口

好处:可以抛出异常,可以带返回值

使用:

//1. 自定义类实现callable接口
MyCallable implements callable<返回值类型>{}
//2. 重写call方法(必须有返回值,和上面的范形一样)

//3. 创建执行服务
ExcutorService ser = Excutors.newFixedThreadPool(3);//创建的线程个数
//4. 提交执行
Future<> f1 = ser.submit(myCallable);//有几个就提交几个
//5. 获取结果
返回值类型 rf1 = f1.get();
//6. 关闭服务
ser.shutdownNow();

2. 并发问题(火车票)

对数据number处理问题

public class TichetProblem implements Runnable{
    private int number = 10;
    @Override
    public void run() {
        while(true){
            if(number<= 0){
            break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ "拿到了第" + number-- +"张ticket");}
    }
    public static void main(String[] args) {
        //只有一个实例对象
        TichetProblem tichetProblem = new TichetProblem();
        //四个人抢票:
        new Thread(tichetProblem, "北京人").start();
        new Thread(tichetProblem, "广东人").start();
        new Thread(tichetProblem, "新疆人").start();
        new Thread(tichetProblem, "台湾人").start();
    }
}

3. 静态代理模式

类似python装饰器,重点:真实对象和代理对象都要实现相同的接口, 类似于组合

一个实现了结婚接口的人,去找实现了结婚接口的婚前公司包装,结婚公司代理这个人结婚。

真实对象专注于一件事,

代理对象可以对真实对象进行包装。

public class StaticProxy {
    public static void main(String[] args) {
        new weddingCompany(new Person()).getMarry();
    }
}
interface Marry {
    void getMarry();
}
class Person implements Marry{
    @Override
    public void getMarry() {
        System.out.println("today");
    }
}
class weddingCompany implements Marry{

    private Person person;

    public weddingCompany(Person person) {
        this.person=person;
    }

    @Override
    public void getMarry() {
        before();
        this.person.getMarry();
        after();
    }
    private void before(){
        System.out.println("before");
    }
    private void after(){
        System.out.println("after");
    }
}

4. lambda表达式

函数式接口:只有一个方法的接口:如Runnable接口只有一个run()方法。

对函数式接口,可以使用lambda表达式创建实现该接口的对象。

(可以用接口类型去new对象,但此时对象只有接口中所定义的方法,和父类引用指向子类对象一样)

InterfaceType user1 = new User1();//其中user1没有User1中定义的其他函数

简化流程:

public class LambdaTest {
    public static void main(String[] args) {
        //1. 接口下方写class实现接口,再调用 普通调用
        //2. main方法前面写静态类,然后再调用 静态内部类
        //3. 把类写到main方法里 然后调用    局部内部类
        //4. 用接口创建,匿名内部类
        IL il = new IL() {
            @Override
            public void l(int a) {
                System.out.println(a);
            }
        };
        il.l(123);
        //5. lambda 表达式
        IL il2 = (int a) -> { System.out.println(a); };
        il2.l(123);
        //简化一,去掉参数类型//常用的表达式
        IL il_1= a->{ System.out.println(a); };
        //简化二,去掉括号(如果有多行,则不能简化{},只能简化()
        IL il_2 = a-> System.out.println(a);
    }
}
interface IL{
    void l(int a);
}
class il implements IL{
    @Override
    public void l(int a) {
        System.out.println(a);
    }
}

5. 线程状态

5个状态,创建状态,就绪状态,运行状态,阻塞状态,死亡状态

.start()从创建到就绪,

线程状态

1. 线程停止

//1. 实现runnalble接口的自定义类中定义一个flag
//2. run方法中写当flag为true时运行
//3. 自定义类中写一个方法使flag为False
//4. main函数中调用3方法,使得线程停止

2. 线程休眠(模拟网络延时,倒计时)

会抛出异常,休眠时间到达之后进入就绪状态

每个对象都有一把锁,sleep不会释放锁

1000ms = 1s

//获取当前时间
Date startData = new Date(System.currentTimeMillis());
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startData));

3. 线程礼让 yield

礼让是指,CPU正在运行的线程从运行状态转变为就绪状态,不是阻塞状态!,

然后让两个线程继续竞争,所以礼让不一定成功,看CPU调度哪一个

4. 线程插队 Join

Thread thread = new Thread(new Myrun());
thread.start();
//在主线程中可写:
thread.join();//来强制执行此线程

5. 获取线程状态

写主函数里,要有实例化的线程或者代理名。

死亡之后的线程不能再次被启动

Thread.State state = new thread.getState();//新建一个state,new的是已经实例化的Thread
state = thread.getState();//状态更新

6. 线程优先级

java提供一个线程调度器监控启动后所有进入就绪状态的线程

优先级只是一个参考,并不是完全按照优先级进行调度的性能倒置,

优先级范围:1-10 Thread.MIN_PRIORITY =1, Thread.MAX_PRIORITY = 10, Thread.NORM_PRIORITY = 5,参考jdk文档

获取和改变:

getPriority(), setPriority(int priorityNumber)

7. 守护线程 Daemon /'di: men/

线程分为用户线程和守护线程,(用户线程有:main,自己的线程;守护线程有gc垃圾回收,自己设置的守护线程)

虚拟机必须确保用户线程执行完毕,不需要确保守护线程执行完毕。

所有的线程默认都是用户线程,thread.setDaemon 默认值为 false,

当值设置为true时,设置为守护线程

虚拟机不需要等待守护线程执行完毕

//thread时实例化的线程
thread.setDaemon(true);

6. 线程同步

多个线程对同一个资源进行操作

同步解决: 队列+ 锁机制 synchronized

ticket问题出现负数的问题:所有人将1拷贝到自己的线程内存中,线程内存操作之后再修改station中的余额,出现-1问题

线程的不安全:对同一资源操作覆盖问题

1. synchronized 修饰符

通过修饰,当获取到对象的锁的时候,才能被执行。缺点:当一个大方法被修饰时,运行效率很低

同步方法和同步块锁的对象时变化的统一资源

//1. 同步方法
// 同步方法锁了之后,默认锁的是该方法所在的对象,如果修改的统一资源存在于该对象中,则用此方法
public synchronized void method(){}
//2. 同步块
// 把同步的对象名放在obj位置,后面是修改统一资源的方法体
synchronized(obj){}

2. JUC包,java.util.concurrent

CopyOnWriteArrayList//JUC里的安全类型list

7. 死锁

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得的资源,再未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

(口红,镜子问题)

8. 显式定义锁接口:Lock

ReentrantLock类实现了Lock锁

可重入锁

class A{
    private final ReentrantLock lock = new ReentrantLock():
    public void m(){
        lock.lock();
        try{
            //主代码
        }finally{
            lock.unlock();
        }
    }
}

9. 线程协作(生产者消费者问题)

  1. 利用缓冲区解决:管程法
wait();//线程一直等待,知道有其他线程唤醒
notifyAll();//唤醒别的所有等待的线程

10. 线程池

ExecutorService excutor = Executors.newFixedThreadPool(10);
excutor.execute();
excutor.shutdown();
这篇关于[Java 多线程 01] 初级多线程 2011.11.13!!!的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!