java基础—线程

Java线程

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。

这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

线程生命周期

在这里插入图片描述

创建线程的方法:

  • 继承Thread类
  • 实现Runnable 接口
线程Thread对象常用方法
方法名方法描述
public void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
public void run()如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
public final void setName(String name)改变线程名称,使之与参数 name 相同。
public final void setPriority(int priority)更改线程的优先级。注意:先设置优先级,在启动start()。
public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。
public final void join(long millisec)等待该线程终止的时间最长为 millis 毫秒。
public final void join()插队,等待插队的线程执行完毕才能执行其他线程。
public void interrupt()中断线程。
public final boolean isAlive()测试线程是否处于活动状态。
public State getState()查看线程状态,
线程的静态方法
方法名方法描述
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
public static void sleep(long millisec)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
public static boolean holdsLock(Object x)当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
public static Thread currentThread()返回对当前正在执行的线程对象的引用。
public static void dumpStack()将当前线程的堆栈跟踪打印至标准错误流。
1.继承Thread的例子
public class Thread01 extends Thread{
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println("我是线程------"+i);
        }
    }
    public static void main(String[] args) {
        Thread01 thread01 = new Thread01();
        //调起线程进入就绪状态,线程之间交互执行,由cpu决定(主线程会优先获取资源执行(1次或多次),之后还是看cpu调度资源进行交互执行)
        //不要调用run方法,不然就无法体现多线程了。
        thread01.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("我是主线程"+i);
        }
    }
}

2. 实现Runnable接口的例子
public class Runnable01 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我是线程-------"+i);
        }
    }

    public static void main(String[] args) {
        Runnable01 runnable01 = new Runnable01();
        //需要new一个Thread,由于start()方法是Thread的方法,runnable并没有
        Thread thread = new Thread(runnable01);
        //开启线程
        thread.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("我是主线程"+i);
        }
    }
}

  • 采用实现 Runnable接口的方式创建多线程时,线程类只是实现了 Runnable 接口,还可以继承其他类。
  • 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
3. sleep方法,线程休眠

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

  • 一般用来模拟网络延迟请求,倒计时等

例子:

import javax.xml.crypto.Data;
import java.text.SimpleDateFormat;
import java.util.Date;

//通过sleep()来模拟倒计时和当前时间
public class TenDoown {
    public static void main(String[] args) throws InterruptedException {
        TenDoown tenDoown = new TenDoown();
//        tenDoown.tenDown();
        tenDoown.currentTime();
    }
    //倒计时十秒
    public void tenDown() throws InterruptedException {
        for (int i = 10; i >=0; i--) {
            Thread.sleep(1000);
            System.out.println(i);
            if(i==0){
                System.out.println("时间到!!!");
                break;
            }
        }
    }
    //获取当前时间,每秒更新
    public void currentTime() throws InterruptedException {
        Date date = new Date(System.currentTimeMillis());//当前系统时间
        System.out.println(date);
        while (true){
            Thread.sleep(1000);//线程每一秒执行
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
            date=new Date(System.currentTimeMillis());//更新当前时间
        }
    }
}

4.线程礼让yield

暂停当前正在执行的线程对象,使其从运行状态->就绪状态,然后与就绪状态下的其他线程重新竞争资源(所以线程礼让不一定成功,可能下一次还是礼让线程被调用)

/*
* 线程礼让yield,不一定成功。
* 礼让只是当前线程从运行状态->就绪状态,然后与其他线程再重新竞争资源
* */
public class ThreadYield {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        new Thread(myThread,"线程a").start();
        new Thread(myThread,"线程b").start();
    }
}
class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始");
        //线程礼让
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"结束");
    }
}

5. 线程插队 join

线程插队,会让当前插队的线程还没执行完的线程,执行完毕后,才给其他 线程资源

public class ThreadJoin  implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我插一下队"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadJoin threadJoin = new ThreadJoin();
        Thread thread = new Thread(threadJoin);
        thread.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("排排队"+i);
            if(i==50){
                thread.join();//当i=12时刻,线程插队执行,将剩下的全部在这里执行完毕
            }
        }
    }
}

6. 线程种类
  • java中线程有用户线程(一般我们写的默认都是,main就是一个用户线程)和守护线程(后台记录操作日志,垃圾回收等)
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
package com.suzezhi.thread;

public class Thread01  {
    public static void main(String[] args) {
        ThreadUser user = new ThreadUser();
        new Thread(user).start();

        //守护线程
        ThreadDemon threadDemon = new ThreadDemon();
        Thread thread = new Thread(threadDemon);
        thread.setDaemon(true);//设置为守护线程
        thread.start();
    }
}

//用户线程
class ThreadUser implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("我是用户线程");
        }
    }
}
//守护线程
class ThreadDemon implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("我是守护线程");
        }
    }
}
7. 线程同步synchronized
  • 同步进行增删改的对象
  • 同步方法,执行在方法返回值类型前加上synchronized
  • 同步块:synchronized(obj){},obj是监听的对象,把要监听的代码放到{}里面
//同步方法
package com.suzezhi.syn;
//模拟买票
public class BuyTricket implements Runnable {
    private int nums=50;
    boolean flag=true;//用来中断线程的状态
    @Override
    public void run() {
        while (flag){
            buy();
            --nums;
        }
    }
    //买票的方法,为了防止出现插队的情况(就是保证线程安全),对方法进行同步
    public synchronized void buy(){
        if(nums<=0){
            flag=false;
            return;
        }
        try {
            Thread.sleep(100);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"买到票号:"+nums);
    }

    public static void main(String[] args) {
        BuyTricket buyTrick = new BuyTricket();
        new Thread(buyTrick,"学生").start();
        new Thread(buyTrick,"老师").start();
        new Thread(buyTrick,"老六").start();
    }
}

//同步块
package com.suzezhi.syn;

public class Bank {
    public static void main(String[] args) {
        Account account = new Account("房钱", 500);
        Drawing self = new Drawing(account, 300, "自己");
        Drawing wife = new Drawing(account, 400, "妻子");

        self.start();
        wife.start();
    }
}

//账户
class Account{
     String name;
     int money;

    public Account(String name, int money) {
        this.name = name;
        this.money = money;
    }
}

// 模拟银行取钱
class Drawing extends Thread{
    private Account account;
    //取钱
    private int drawingMoney;
    //手上的钱
    private int nowMoney;

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
    @Override
    public void run() {
        synchronized (account){
            if(account.money-drawingMoney<0){
                System.out.println(this.getName()+":账户余额不足!!");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //账户额度
            account.money=account.money-drawingMoney;
            //手上的钱
            nowMoney=nowMoney+drawingMoney;
            System.out.println(this.getName()+"取:"+drawingMoney+"万");
            System.out.println(account.name+"余额:"+account.money+"万");
            System.out.println(this.getName()+"手上:"+nowMoney+"万");
        }

    }

}

8. 死锁

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

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

public class SiLock {
    public static void main(String[] args) {
        Cat cat = new Cat();
        Dog dog = new Dog();
        GetCatAndGod t1 = new GetCatAndGod(0,"小明",cat,dog);
        GetCatAndGod t2 = new GetCatAndGod(1,"小红",cat,dog);

        t1.start();
        t2.start();
    }
}

class Cat{}
class Dog{}

class GetCatAndGod extends Thread{
    int chose;
    Cat cat;
    Dog dog;
    public GetCatAndGod(int chose,String name,Cat cat,Dog dog) {
        super(name);
        this.chose = chose;
        this.cat=cat;
        this.dog=dog;
    }
    @Override
    public void run() {
        getCatAndGod();
    }
    public void getCatAndGod(){
        if(chose==0){
            synchronized (cat){
                System.out.println(this.getName()+"拿到猫");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //资源被占用会出现死锁
//                synchronized (dog){
//                    System.out.println(this.getName()+"想拿到狗");
//                }
            }
            synchronized (dog){
                System.out.println(this.getName()+"想拿到狗");
            }
        }else {
            synchronized (dog){
                System.out.println(this.getName()+"拿到狗");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //资源被占用会出现死锁
//                synchronized (cat){
//                    System.out.println(this.getName()+"想拿到猫");
//                }
            }
            synchronized (cat){
                System.out.println(this.getName()+"想拿到猫");
            }
        }
    }
}
9. Lock锁

ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

package lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RableLock implements Runnable {

    private int nums=50;
    ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        try{
            //加锁
            lock.lock();
            while (true){
                if(nums<=0){
                    return;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+(nums--));
            }
        }finally {
            //解锁
            lock.unlock();
        }

    }

    public static void main(String[] args) {
        RableLock rableLock = new RableLock();
        new Thread(rableLock,"学生").start();
        new Thread(rableLock,"老师").start();
        new Thread(rableLock,"老六").start();
    }
}

10. 线程池
  • JDK 5.0起提供了线程池相关APl: ExecutorService和Executors
  • ExecutorService:真正的线程池接。常见子类ThreadPoolExecutor:
    • void execute(Runnable command)∶执行任务/命令,没有返回值,一般用来执行Runnable
    • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
package com.suzezhi.pool;

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

//测试线程池
public class TestPool implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        TestPool t1 = new TestPool();
        TestPool t2 = new TestPool();
        TestPool t3 = new TestPool();

        //创建一个线程池服务
        ExecutorService service = Executors.newFixedThreadPool(10);
        //调用Runnable线程
        service.execute(t1);
        service.execute(t2);
        service.execute(t3);
        //关闭线程池
        service.shutdown();
    }
}


Lambda表达式
  • Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

  • 必须是函数式接口,就是一个接口只有一个函数的时候,才可以用lambda表达式。

public class Test{
    public static void main(String[] args){
        Lambda1 l=()->{
            System.out.print("这是lambda表达式");
        }
        l.test();
    }
}
interface Lambda1{
    void test();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值