java中的线程

知识模块
一.进程和线程概述:
二.创建线程的第一种方式
三.Thread类的常用方法
四.创建线程的第二种方式
五.第三种创建方式
六.多线程安全问题




一.进程和线程概述:
    进程:操作系统中运行的程序对应一个或多个进程
    线程:一个进程中至少有一个线程,线程控制着进程的执行

二.创建线程的第一种方式
     //线程定义
        class 类名 extends Thread{
            public void run(){
                //定义线程要执行的程序
            }
        }
    /* 创建线程并启动*/
    创建该类对象然后调用start()方法
/*
自定义线程
 */
public class Thread01 extends Thread {
    public void run() {
        //线程要执行的任务
        for (int i = 0; i < 10; i++) {
            System.out.println("run..."+i);
        }
    }
}
/*
自定义线程
参照自定义异常思想
class AgeException extends Exception/RuntimeException{

}
class Dog extends Animal{

}
  同理可得
  class 类名 extends ???{

  }
  多线程运行特点:
     CPU在多个线程之间做着随机切换执行操作,无论如何切换,最终一定会把每个线程
     任务执行完
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        Thread01 t1 = new Thread01();
        //t1.run();t1.run()仅仅相当于通过对象调用方法,不会去创建一个线程
        t1.start();//创建一个线程并启动

        for (int i = 0; i < 10; i++) {
            System.out.println("main..." + i);
        }
    }
}
三.Thread类的常用方法
      Thread类中的方法
          static Thread currentThread()
                获取当前执行的线程对象
          String getName()
                底层再给线程起名的时候默认是从0开始
                Thread-0,Thread-1....
          static void sleep(long millis)
                可以让指定的线程休眠指定的毫秒值,当指定的毫秒值时间一到,该线程会自动醒来
                当CPU再次切换到该线程的时候,会继续执行

/*
自定义线程
缺点:
class A extends B,Thread{//Java不支持多继承

}


 */
public class Thread01 extends Thread {
    public void run() {
        //线程要执行的任务
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"..."+i);
        }
    }
}
/*
Thread类中的方法
    static Thread currentThread()
          获取当前执行的线程对象
    String getName()
          底层再给线程起名的时候默认是从0开始
          Thread-0,Thread-1....
    static void sleep(long millis)
          可以让指定的线程休眠指定的毫秒值,当指定的毫秒值时间一到,该线程会自动醒来
          当CPU再次切换到该线程的时候,会继续执行
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        Thread01 t1 = new Thread01();
        //t1.run();t1.run()仅仅相当于通过对象调用方法,不会去创建一个线程
        t1.start();//创建一个线程并启动

        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"..." + i);
        }
    }
}
四.创建线程的第二种方式
    class 类名 implemetns Runnable{
        public void run(){
          //定义线程要执行的任务
        }
    }
    /* 创建该线程并启动*/
    new Thread(new 类名()).start();

public class Thread01 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " ... " + i);
        }
    }
}
/*
Thread类的构造方法
    Thread(Runnable target)
          分配新的 Thread 对象。
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        Thread01 t1 = new Thread01();
        new Thread(t1).start();//new Thread()创建线程对象
                               //t1实现了Runnable接口,重写了run()方法,传给Thread()构造方法,相当于将线程要执行的任务传递给该线程
                               //最后调用start()方法会在底层创建并启动该线程
        new Thread(t1).start();//又创建一个新的线程,执行的还是一样的任务
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "... " + i);
        }
    }
}
五.第三种创建方式
       线程第三种创建方式:匿名内部类
       格式:
           new 父类/父接口(){
             //重写父类或父接口的方法
           };
           原理:
             父类
              class 类名 extends 父类{
                 //重写父类的方法
              }
              new 类名();
             父接口
              class 类名 implement 父接口{
                 //实现父接口方法
              }
              new 类名();
       实现代码1:
       new Thread() {
                  public void run() {
                      for (int i = 0; i < 10; i++) {
                          System.out.println(getName() + "..." + i);
                      }
                  }
              }.start();

       实现代码2:
       new Thread(new Runnable() {
                   public void run() {
                       for (int i = 0; i < 10; i++) {
                           System.out.println(Thread.currentThread().getName() + " " + i);
                       }
                   }
               }).start();

/*
线程第三种创建方式:匿名内部类
格式:
    new 父类/父接口(){
      //重写父类或父接口的方法
    };
    原理:
      父类
       class 类名 extends 父类{
          //重写父类的方法
       }
       new 类名();
      父接口
       class 类名 implement 父接口{
          //实现父接口方法
       }
       new 类名();

 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        //method01();
        /*
         class 类名 implemetns Runnable{
        public void run(){
          //定义线程要执行的任务
        }
    }
          new Thread(new 类名()).start();
         */
      /*  Runnable r = new Runnable() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                }
            }
        };
        new Thread(r).start();*/

        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                }
            }
        }).start();

       /* new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                }
            }
        }).start();*/

    }

    private static void method01() {
    /*  //线程定义
      class 类名 extends Thread{
          public void run(){
              //定义线程要执行的程序
          }
      }*/
        /*Thread t = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(getName() + "..." + i);
                }
            }
        };
        t.start();*/
        new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(getName() + "..." + i);
                }
            }
        }.start();
    }
}
六.多线程安全问题
   a.产生原因
       由于多个线程操作同一份共享资源,其中一个线程还没有执行完操作共享数据的代码,CPU切换到
       其他线程去执行,最终导致共享数据报错误
public class Ticket implements Runnable {
    private int ticket = 100;

    @Override
    public void run() {
        //卖票
        while (true) {
            if (ticket>0) {
             /*   try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
               // System.out.println(Thread.currentThread().getName()+"..."+ticket--);
                System.out.println(Thread.currentThread().getName()+"..."+ticket);
                ticket--;
            }
        }
    }
}
/*
多线程卖票:
 三个窗口去卖100张票
 A窗口    B窗口    C窗口
 100      98       95
 99       97       94
          96
  ..      ..       ..
  我们考虑用线程去模拟窗口,线程执行任务为卖票(输出语句)

  卖票案例的第一个问题:
     1.卖出0票和-1票
     2.卖出重复票
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(t,"A窗口").start();//模拟窗口A
        new Thread(t,"B窗口").start();//模拟窗口B
        new Thread(t,"C窗口").start();//模拟窗口C
    }
}
   b.解决方案
       1.同步代码块:保证其中一个线程在操作共享数据的时候不被其他线程打扰
              保证多线程操作共享资源的安全性
              使用同步代码块保证多线程安全性
              格式:
                synchronized(锁对象){
                   我们一般将操作共享资源的代码梵高同步代码块中
                }
                 锁对象指的是new出来的任意对象
                 1.如果某个线程进入同步代码块,该线程会持有该锁对象,其他线程就无法在进入同步代码块同时也无法持有该锁对象
                 2.如果某个线程走出同步代码块,该线程会释放该锁对象,此时其他某一个线程可以进入同步代码块同时可以持有该锁对象

                 注意:
                    所有的线程享有同一个锁对象才能保多线程操作共享资源安全性

public class Ticket implements Runnable {
    private int ticket = 100;

    @Override
    public synchronized void  run() {
        //卖票
        while (true) {

                if (ticket>0) {

                    System.out.println(Thread.currentThread().getName()+"..."+ticket--);
                }
            }
    }
}
/*
保证多线程操作共享资源的安全性
使用同步代码块保证多线程安全性
格式:
  synchronized(锁对象){
     我们一般将操作共享资源的代码梵高同步代码块中
  }
   锁对象指的是new出来的任意对象
   1.如果某个线程进入同步代码块,该线程会持有该锁对象,其他线程就无法在进入同步代码块同时也无法持有该锁对象
   2.如果某个线程走出同步代码块,该线程会释放该锁对象,此时其他某一个线程可以进入同步代码块同时可以持有该锁对象

   注意:
      所有的线程享有同一个锁对象才能保多线程操作共享资源安全性
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(t,"A窗口").start();//模拟窗口A
        new Thread(t,"B窗口").start();//模拟窗口B
        new Thread(t,"C窗口").start();//模拟窗口C
    }
}
       2.同步方法:
              同步方法解决多线程安全问题:
               格式:
                   修饰符 synchronized 返回值类型 方法名(参数列表){

                   }
                   同步方法相当于:
                   synchronized(this){//this引用指向new Thread()中传入的对象
                      //对方法中所有代码同步
                   }
                   我们一般将涉及到操作共享数据的方法单独抽取到一个方法中,然后在这个方法上加synchronized


/*
同步方法解决多线程安全问题:
 格式:
     修饰符 synchronized 返回值类型 方法名(参数列表){

     }
     同步方法相当于:
     synchronized(this){//this引用指向new Thread()中传入的对象
        //对方法中所有代码同步
     }
     我们一般将涉及到操作共享数据的方法单独抽取到一个方法中,然后在这个方法上加synchronized
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(t,"A窗口").start();//模拟窗口A
        new Thread(t,"B窗口").start();//模拟窗口B
        new Thread(t,"C窗口").start();//模拟窗口C
    }
}
public class Ticket implements Runnable {
    private int ticket = 100;

    /*@Override
    public synchronized void  run() {
        //卖票
        while (true) {

                if (ticket>0) {

                    System.out.println(Thread.currentThread().getName()+"..."+ticket--);
                }
            }
    }*/
  /*  @Override
    public void run() {
        synchronized (this) {
            System.out.println(this);

            //卖票
            while (true) {

                if (ticket > 0) {

                    System.out.println(Thread.currentThread().getName() + "..." + ticket--);
                }
            }
        }
    }*/
    public void run() {
            while (true) {
                sellTicket();
            }
        }

    private synchronized void sellTicket() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "..." + ticket--);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值