多线程使用

1.什么是进程?

简单理解 就是 正在运行的程序就是进程;

每个程序有个独立的进程,而进程之间是相互独立存在的;

2.什么是线程?

进程 运行需要线程,进程运行可以有多个线程,但进程只要需要一个线程。

3.什么是多线程?

多线程就是串行和并行两个概念;

串行:就是单条线来执行的,前一个执行完才能执行后一个,

并行:多条线同时进行,同步执行任务;

比如在下载多个文件,串行就是先把前一个文件下载完,再下载后一个文件,这样下载效率慢。

并行就可以一次性同步下载多个文件,这样充分利用资源,可以提高下载效率。

4.如何使用线程

第一种继承Thread 方式  ;

public class Demo extends Thread {
    @Override
    public void run(){

        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"---run线程---"+i);
        }

    }
}
public class TestThread {

    public static void main(String[] args) {

        Demo demo = new Demo();
        demo.setName("线程1");
        demo.start();

       Demo demo1 = new Demo();
       demo1.setName("线程2");
       demo1.start();
    }
}

Thread.currentThread().getName()是命名线程名,会有一个默认的线程名,没有给线程输入名称就会用默认名。

还有一种this.getName()也可以进行命名,但是不常用 ,

第二种实现Runnable接口;

public class Demo2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+" --------"+i);
        }
    }
}
public class TestRunnable {

    public static void main(String[] args) {
        //创建一个线程任务
        Demo2 demo2 = new Demo2();

        Thread thread = new Thread(demo2,"线程一");
        thread.start();
        Thread thread2 = new Thread(demo2,"线程二");
        thread2.start();
    }
}

 这两种方式  在写法上没什么太大的区别 ,用实现Runnable接口多一些,因为 继承Thread方式,子类一次只能继承一个父类,使用不太方便。

5.常用方法

1.休眠:public static viod sleep(long  millis) 当前线程 主动休眠 millis 秒

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                //休眠  每隔一段时间 执行一次
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //获取线程名称
            System.out.println(Thread.currentThread().getName()+"------"+i);
        } 

2.放弃:public static viod yield()当前线程主动放弃时间片,回到就绪状态竞争下一次时间片

public static void main(String[] args)  {
        MyThread myThred = new MyThread();

        myThred.setName("  ");
        myThred.start();

            //放弃
        myThred.yield();

        for (int i = 0; i < 20; i++) {
            System.out.println("main------"+i);
        }
    }

3.加入:public static void join()       允许其他线程加入到当前线程中,并其他线程执行完毕后,当前线程才会执行。

 public static void main(String[] args)  {
        MyThread myThred = new MyThread();
    
        myThred.setName("  ");
        myThred.start();
        try {
            myThred.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        for (int i = 0; i < 20; i++) {

            System.out.println("main------"+i);
        }

    }

4.优先级:  线程对象 .setPriority()

线程优先级分为1-10,默认是5,等级越高,表示获取cpu  概率越高

public static void main(String[] args)  {
    MyThread myThred = new MyThread();
    MyThread myThred2 = new MyThread();

    myThred.setPriority(3);
    myThred.setName("111  ");
    myThred.start();

    myThred2.setPriority(10);
    myThred2.setName("222  ");
    myThred2.start();

}

5.守护线程:  线程对象.setDaemon(true);设置为守护线程。

线程有两类:用户线程(前台线程)和 守护线程(后台线程)

程序中前台线程执行完毕,后台线程也会自动结束;

public static void main(String[] args)  {
    MyThread myThred = new MyThread();
    MyThread myThred2 = new MyThread();

    myThred.setDaemon(true);
    myThred.setPriority(3);
    myThred.setName("111  ");
    myThred.start();

    myThred2.setPriority(10);
    myThred2.setName("222  ");
    myThred2.start();

}

6.做两个小案例

卖票   A,B,C三个窗口各买100张票

public class Demo extends Thread {
    private int ticket=100;
    @Override
    public void run(){
        while (true){
            if(ticket>0){
                ticket--;
                System.out.println(Thread.currentThread().getName()+"卖了一张票还剩"+ticket+"张");
            }

        }

    }


public class Demo extends Thread {
    private int ticket=100;
    @Override
    public void run(){
        while (true){
            if(ticket>0){
                ticket--;
                System.out.println(Thread.currentThread().getName()+"卖了一张票还剩"+ticket+"张");
            }

        }

    }

A,B,C三个窗口 共同卖100张票

public class Demo2 implements Runnable{
    private int ticket=100;
    @Override
    public void run() {

        while (ticket>0){
            ticket--;
            System.out.println(Thread.currentThread().getName()+"买了一张票还剩"+ticket+"张");
        }
    }
}

public class TestRunnable {

    public static void main(String[] args) {
        //创建一个线程任务
        Demo2 demo2 = new Demo2();

        Thread thread = new Thread(demo2,"A");
        thread.start();
        Thread thread2 = new Thread(demo2,"B");
        thread2.start();
        Thread thread3 = new Thread(demo2,"C");
        thread3.start();
    }
}
 

 

第二个A,B,C三个窗口 共同卖100张票时 打印的出来的结果 出现了重复和超出的问题, 这些问题就是线程安全问题,下面来看看线程安全问题。

7.线程安全问题

多个线程共享一个资源时,可能会出现线程安全问题

当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致

临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性

原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省

7.2如何保证线程安全性?

1.同步代码块

synchronized(临界资源对象){//对临界资源对象加锁

//代码 (原子操作)
        }

2.

Lock lock= new ReentrantLock()

lock.lock()

//代码

lock.unlock();

public class arr {
        private static String[] arr= new String[2];
        private static int index=0;
       private static Lock lock=new ReentrantLock();
    public static void main(String[] args) {

        //创建一个线程类 并为其指定任务
          Thread thread=new Thread(new Runnable() {
              @Override
              public void run() {
                synchronized (arr){ //自动开启锁 和自动释放锁
                  if(arr[index]==null){
                      arr[index]="hello";
                      index++;
                  }
                }
              }
          });

        Thread thread2=new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();//手动开启锁
                if(arr[index]==null){
                    arr[index]="world";
                    index++;
                }
                lock.unlock();//手动释放锁

            }
        });
        //开启线程
        thread.start();
        thread2.start();
        //先加执行完thread,thread2线程,再执行main主线程
        try {
            thread.join();
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Arrays.toString(arr));

    }
}

 这样就也能 解决 上边案例 的线程 重复,超出的问题

注意: 每个对象都有一个互斥锁标记, 用来分配给线程。

只有拥有对象互斥锁标记的线程,才能进入该对象加锁的同步代码块。

线程退出同步代码块,会释放相应的互斥锁标记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值