Java基础--线程

来源:互联网 发布:批量图片透明度软件 编辑:程序博客网 时间:2024/05/21 08:58
package cn.itcast.thread;
/*
进程:正在执行的程序称作为一个进程。进程负责了内存空间的划分


        问题:Windows号称是多任务的操作系统,那么Windows是同时运行多个应用程序吗?


       从宏观的角度:Windows确实是在同时运行多个应用程序
       从微观的角度看:cpu是做了一个快速切换执行的动作,由于速度太快,所以我们感觉不到在切换
   
       单核的CPU在一个时间片中只能执行一个应用程序
        各个应用程序其实是在做cpu的资源争夺战,cpu做了快速切换。
   
         与其说是进程在做cpu的争夺战,还不如说是线程在做CPU的资源争夺战。
   
   线程:线程在一个进程中负责了一个代码的执行,,就是进程中一个执行路径
   
   多线程:在一个进程中有多个线程同时执行不同的任务
   
疑问:线程负责了代码的执行,我们之前没有学过线程,为什么代码可以执行


任何一个Java程序,jvm在运行的时都会创建一个main线程执行main方法中的所有代码


一个Java应用程序至少有几个线程?
    至少有两个线程,一个是主线程负责main方法代码执行,一个是垃圾回收器线程,负责了回收垃圾


 多线程的好处:
 1.解决了一个进程能同时执行多个任务的问题
 2.提高了资源的利用率而不是效率
 
 
 多线程的弊端:
   
   1.增加了cpu的负担
   2.降低了一个进程中线程的执行概率
   3.引发了线程安全问题
   4.出现思死锁现象
   
  如何创建多线程:
  
          创建线程的方式:
          1.自定义一个类继承Thread类
          2.重写Thread类的run方法
                                                疑问:为甚么要重写run方法的目的是什么?
                                            每个线程都有自己的任务代码,jvm创建的主线程的任务代码就是main方法中的所有代码。自定义线程的任务代码就写在run方法中,自定义线程负责了run方法中的代码
          3.创建Thread的子类对象,并且调用start方法开启线程。
          一个线程一旦开启,那么线程就会执行run方法中的代码,run方法千万不能直接调用,直接调用run方法相当于调用了一个普通的方法而已,并没有开启新的线程
 2M带宽
 迅雷下载是多线程下载的
         黄飞鸿 英雄有梦  网速100kb/s
         变形金刚             100kb/s(利用起来空闲带宽)
 




 */


public class Demo1 extends Thread {


@Override//把自定线程的任务代码写在run方法中
public void run() {
for(int i = 0;i<100;i++){
System.out.println("自定义线程:"+i);
}

}


public static void main(String[] args) {
//创建了自定义的线程对象
Demo1 d = new Demo1();
//调用start 方法启动线程
d.start();
for(int i = 0;i<100;i++){
System.out.println("main线程:"+i);
}


}


}



package cn.itcast.thread;
/*
 需求:模拟QQ视频与聊天同时在执行。
 
 */
class TalkThread extends Thread{


@Override
public void run() {
while(true){
System.out.println("hi,你好!开视频");
}
}

}


class VideoThread extends Thread{


@Override
public void run() {
while(true){
System.out.println("视频视频");
}
}

}
public class Demo2 {


public static void main(String[] args) {
TalkThread talkthread = new TalkThread();
talkthread.start();
VideoThread videoThread = new VideoThread();
videoThread.start();




}


}






package cn.itcast.thread;
/*
 
 线程的生命周期
 
 
 CPU的等待资格
 
 CPU的执行权
 
 创建                                                                    start         可运行状态                  得到cpu的执行权                          运行状态                                          完成任务       死亡状态
 new 线程对象                                                                                         具备等待CPU的资格              被抢夺了CPU的执行权        具备等待CPU的资格                                    
    
                                                                                                                            不具备CPU的执行权                  可以互相切换的                    具备CPU的执行权




临时阻塞状态:


 运行状态下的线程一旦执行了sleep或者wait方法之后,那么该线程会进入临时阻塞状态下,如果线程调用了sleep方法进入临时阻塞状态
 那么线程一旦超过了指定的睡眠时间,那么就会重新进入可运行状态,如果调用了wait方法进入的临时阻塞状态,那么需要其他线程唤醒该线程
 才可以重新进入可运行状态
 
 
线程常用的方法:


 Thread(String name)     初始化线程的名字
 getName()             返回线程的名字
 setName(String name)    设置线程对象名
 sleep() (静态的方法,哪个线程执行了sleep方法就是哪个线程在睡眠)          线程睡眠指定的毫秒数。
 
  currentThread()      返回CPU正在执行的线程的对象    (返回当前线程对象,该方法是静态方法,注意:哪个线程执行了currentThread()代码就返回那个线程的对象)
 getPriority()             返回当前线程对象的优先级   默认线程的优先级是5
 setPriority(int newPriority) 设置线程的优先级    虽然设置了线程的优先级,但是具体的实现取决于底层的操作系统的实现(最大的优先级是10 ,最小的1 , 默认是5)。




   
 */
public class Demo3 extends Thread{
public Demo3(String name){
super(name);//调用了Thread类的一个参数的构造方法

}


@Override
public void run() {
for(int i = 0;i<100;i++){
System.out.println(this.getName()+":"+i);
}
/*
System.out.println("this:"+this);
System.out.println("当前的线程对象:"+Thread.currentThread());

for(int i = 0;i<100;i++){
System.out.println(this.getName()+":"+i);
try {
Thread.sleep(1000);//为什么在这里不能抛出异常,只能捕获??Thread类的run方法没有抛出异常类型,所以子类不能抛出异常类型
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
}

public static void main(String[] args) throws InterruptedException{
//创建一个线程对象
Demo3 d = new Demo3("狗娃");
d.setPriority(10);//设置线程的优先级  。优先级的数字越大,优先级越高,优先级的范围是1~10.
d.start();
for(int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}


/*
System.out.println("自定义线程的优先级:"+d.getPriority());//线程的优先级默认是5
System.out.println("主线程的优先级"+Thread.currentThread().getPriority());

System.out.println("d:"+d);
d.start();

//d.sleep(1000);//主线程在睡眠
d.start();//开启线程
d.setName("铁蛋");
 
Thread mainThread = Thread.currentThread();
System.out.println("主线程的名字线程的名字:"+mainThread.getName());
//System.out.println("线程的名字:"+d.getName());
*/
 


}




}





package cn.itcast.thread;
/*
 
 线程的生命周期
 
 
 CPU的等待资格
 
 CPU的执行权
 
 创建                                                                    start         可运行状态                  得到cpu的执行权                          运行状态                                          完成任务       死亡状态
 new 线程对象                                                                                         具备等待CPU的资格              被抢夺了CPU的执行权        具备等待CPU的资格                                    
    
                                                                                                                            不具备CPU的执行权                  可以互相切换的                    具备CPU的执行权




临时阻塞状态:


 运行状态下的线程一旦执行了sleep或者wait方法之后,那么该线程会进入临时阻塞状态下,如果线程调用了sleep方法进入临时阻塞状态
 那么线程一旦超过了指定的睡眠时间,那么就会重新进入可运行状态,如果调用了wait方法进入的临时阻塞状态,那么需要其他线程唤醒该线程
 才可以重新进入可运行状态
 
 
线程常用的方法:


 Thread(String name)     初始化线程的名字
 getName()             返回线程的名字
 setName(String name)    设置线程对象名
 sleep() (静态的方法,哪个线程执行了sleep方法就是哪个线程在睡眠)          线程睡眠指定的毫秒数。
 
  currentThread()      返回CPU正在执行的线程的对象    (返回当前线程对象,该方法是静态方法,注意:哪个线程执行了currentThread()代码就返回那个线程的对象)
 getPriority()             返回当前线程对象的优先级   默认线程的优先级是5
 setPriority(int newPriority) 设置线程的优先级    虽然设置了线程的优先级,但是具体的实现取决于底层的操作系统的实现(最大的优先级是10 ,最小的1 , 默认是5)。




   
 */
public class Demo3 extends Thread{
public Demo3(String name){
super(name);//调用了Thread类的一个参数的构造方法

}


@Override
public void run() {
for(int i = 0;i<100;i++){
System.out.println(this.getName()+":"+i);
}
/*
System.out.println("this:"+this);
System.out.println("当前的线程对象:"+Thread.currentThread());

for(int i = 0;i<100;i++){
System.out.println(this.getName()+":"+i);
try {
Thread.sleep(1000);//为什么在这里不能抛出异常,只能捕获??Thread类的run方法没有抛出异常类型,所以子类不能抛出异常类型
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
}

public static void main(String[] args) throws InterruptedException{
//创建一个线程对象
Demo3 d = new Demo3("狗娃");
d.setPriority(10);//设置线程的优先级  。优先级的数字越大,优先级越高,优先级的范围是1~10.
d.start();
for(int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}


/*
System.out.println("自定义线程的优先级:"+d.getPriority());//线程的优先级默认是5
System.out.println("主线程的优先级"+Thread.currentThread().getPriority());

System.out.println("d:"+d);
d.start();

//d.sleep(1000);//主线程在睡眠
d.start();//开启线程
d.setName("铁蛋");
 
Thread mainThread = Thread.currentThread();
System.out.println("主线程的名字线程的名字:"+mainThread.getName());
//System.out.println("线程的名字:"+d.getName());
*/
 


}




}





package cn.itcast.thread;
/*
 
 
 进程:进程就是正在运行的应用程序。进程负责了内存空间划分。
 
 线程:一个进程中的代码是由线程去执行的,线程也就是进程中一个执行路径。
 
 多线程:一个进程中有多个线程可以同时执行任务
 
 多线程的好处:
    1.解决一个进程中可以同时执行多个任务的问题。
    2。提高了资源利用率。
    
     多线程的弊端:
    1.增加了CPU的负担
    2.降低了一个进程中线程的执行概率
    3.出现了线程安全问题
    4.会引发死锁现象。
    
 自定义线程的实现方式:
    方式一:
     1.自定义一个类继承Thread类。
     2.重写Thread类的run方法,把定义线程的任务代码写在run方法上。
     3.创建Thread的子类对象,并且调用start方法启动一个线程。
     
   注意:千万不要直接调用run方法,调用start方法的时候线程就会开启,线程一旦开启就会执行run方法中的代码,如果直接调用
   run方法,那么就相当于调用了一个普通的方法而已。
   
   线程安全问题:
   
   线程安全出现的根本原因:
     1.存在两个或者两个以上的线程对象共享同一个资源。
     2.多线程操作共享资源的代码有多句。
     
 线程安全问题的解决方案:
     方式一:可以使用同步代码块去解决
     格式:
     synchronized(锁对象){
                                需要被同步的代码块;
     
     }
     
同步代码块要注意的事项:
    1.锁对象可以是任意一个对象
    2.一个线程在同步代码块中使用了sleep并不会释放锁对象。
    3.如果不存在这线程安全问题,千万不要使用同步代码块,因为会降低效率。
    4.锁对象必须是多线程共享的一个资源,否则锁不住
    
 方式二:同步函数就是使用synchronized修饰一个函数
 
 同步函数要注意的事项:
    1.如果一个非静态的同步函数的锁对象是this对象,如果是静态同步函数的锁对象是当前函数所属的类的字节码文件(class对象)
    2.同步函数的锁对象是固定的  ,不能由你来指定的。  
    
    推荐使用同步代码块:
                     原因:
          1.同步代码块的锁对象可以由我们随意指定,方便控制。同步函数的锁对象是固定的,不能由我们来制定。
          2.同步代码块可以很方便控制需要被同步代码的范围,同步函数必须是整个函数的所有代码都被同步了。
    
 需求:一个银行账户有5000块,两个夫妻一个那个存折,一个拿着卡,开始取钱比赛,每次只能取一千块,要求不准出现线程安全问题。
        
    
 */
class BankThread extends Thread{

static int count = 5000;
public BankThread(String name){
super(name);
}
@Override//非静态的同步函数
public synchronized void run() {
            while(true){
            //同步代码块
    synchronized("锁"){
    if(count>0){
    System.out.println(Thread.currentThread().getName()+"取走了1000块,还剩余"+(count-1000)+"元");
        count = count - 1000;
}else{
System.out.println("取光了");
break;
}

          }
}
}

//静态的函数---->函数所属的类的字节码文件对象(创建一个class对象,把类文件的信息全部都保存到该对象中    newclass())---->BankThread.class 唯一的
public static synchronized void getMoney(){




}

}
public class Demo1 {


public static void main(String[] args) {
//创建两个线程对象
BankThread thread1 = new BankThread("老公");
BankThread thread2 = new BankThread("老婆");
//调用start方法开启线程取钱
thread1.start();
thread2.start();


}


}





package cn.itcast.thread;
/*
 
 Java同步机制解决了线程的安全问题,但是也同时引发了死锁现象。
 
 死锁现象:
 
 死锁现象出现的根本原因:
 1.存在两个或者连个以上的线程;
 2.存在两个或者两个以上的共享资源
 
 死锁的解决方案:没有方案。只能尽量避免发生而已。
 */


class DeadLock extends Thread{
public DeadLock(String name){
super(name);
}


@Override
public void run() {
if("张三".equals(Thread.currentThread().getName())){
synchronized("遥控器"){
System.out.println("张三拿到了遥控器,准备去拿电池!!");
}
synchronized("电池"){
System.out.println("张三拿到了遥控器与电池了,开着空调爽歪歪!!");
}

}else if("狗娃".equals(Thread.currentThread().getName())){
synchronized("电池"){
System.out.println("狗娃拿到了电池,准备去拿遥控器!!");
}
synchronized("遥控器"){
System.out.println("狗娃拿到了遥控器与电池了,开着空调爽歪歪!!");
}

}

  }
}
public class Demo2 {


public static void main(String[] args) {
DeadLock thread1 = new DeadLock("张三");
DeadLock thread2 = new DeadLock("狗娃");
//开启线程
thread1.start();
thread2.start();



}





package cn.itcast.thread;
/*
 
 自定义线程:
 
    创建线程的方式:
    
    方式一:
          1.自定义一个类继承Thread类
          2.重写Thread类的run方法
                                                疑问:为甚么要重写run方法的目的是什么?
                                            每个线程都有自己的任务代码,jvm创建的主线程的任务代码就是main方法中的所有代码。自定义线程的任务代码就写在run方法中,自定义线程负责了run方法中的代码
          3.创建Thread的子类对象,并且调用start方法开启线程。
     注意:     一个线程一旦开启,那么线程就会执行run方法中的代码,run方法千万不能直接调用,直接调用run方法相当于调用了一个普通的方法而已,并没有开启新的线程
 
 方式二:
    1.自定义一个类实现Runnable接口
    2.实现Runnable接口的run方法,把自定义线程的任务定义在run方法上。
    3.创建Runnable实现类的对象.
    4.创建hread类的对象,并且把Runnable实现类的对象作为实参传递。
    5.调用Thread对象的start方法开启一个线程
    
    
    问题1:请问Runnable实现类的对象是线程对象么?
    Runnable实现类的对象并不是一个线程的对象,只不过是实现了Runnable接口的对象而已
             只有Thread或者Thread的子类才是线程对象。
             
 问题2:为什么要把Runnable的实现类的对象作为实参传递给Thread对象呢?作用是什么?
 
 作用就是把Runnable实现类的对象的run方法作为了线程的任务代码去执行了
 
 
 推荐使用方式二:实现Runnable接口的。
 
 原因:因为Java是单继承,多实现的。
 
    
    
 */


public class Demo3 implements Runnable{



@Override
public void run() {
System.out.println("this:"+ this);
System.out.println("当前线程:"+Thread.currentThread());
/*
for (int i =0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);

}
*/
}


public static void main(String[] args) {

//创建Runnable实现类的对象
Demo3 d = new Demo3();
//创建Thread类的对象,把Runnable实现类对象作为实参传递
Thread thread = new Thread(d,"狗娃");//Thread类使用Target变量记录了d对象
//调用thread对象的start方法开启线程
thread.start();
/*
for (int i =0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);

}
*/

}
/*
//Thread类的run方法
   @Override
   public void run(){
  if(target!=null){
  target.run();//就相当于Runnable实现类对象的run方法作为了Thread对象的任务代码了。
  }
   }
   */
}





package cn.itcast.thread;


 class SaleTicket implements Runnable{
int num = 50;//票数


@Override
public void run() {
while(true){
synchronized("锁"){
if(num>0){
System.out .println(Thread.currentThread().getName()+"售出了,第"+num+"号票");
   num--;
}else{
System.out .println("售完了");
break;
}
}
}

}


}


public class Demo4 {


public static void main(String[] args) {
//创建一个Runnable实现类的对象
SaleTicket saleticket = new SaleTicket();
//创建三个线程对象模拟三个敞口
Thread thread1 = new Thread(saleticket,"窗口1");
Thread thread2 = new Thread(saleticket,"窗口2");
Thread thread3 = new Thread(saleticket,"窗口3");
//开启线程对象
thread1.start();
thread2.start();
thread3.start();


}


}




package cn.itcast.thread;
/*


 线程的通讯:一个线程完成了自己的任务时,要通知另外一个线程去完成另外一个任务
 
 需求:生产者与消费者
 
 wait():等待  如果线程执行了wait方法,那么该线程会进入等待状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。
 
 notify():唤醒。唤醒线程池中等待线程其中的一个
 
 notifyAll():唤醒线程池中所有等待的线程
 
 wait与notify方法要注意的事项:
     1.wait与notify方法属于Object类对象的。(锁对象可以是任意对象)
     2.wait方法与notify方法必须在同步代码块或者同步函数中才能使用。
     3.wait方法与notify方法必须由锁对象调用。
 
 wait():一个线程如果执行了wait方法,那么该线程就会进入一个以锁对象为标识符的线程池中等待
 notify():如果一个线程执行notify方法,那么就唤醒以锁对象为标识符的线程中等待线程中的其中一个
 
 问题一:出现了线程安全问题。价格错乱了
 
 */


//产品类


class Product{
String name;//名字
double price;//价格
boolean flag = false;//产品是否生产完毕的标识

}


//生产者


class Producer extends Thread{
Product p;//产品
public Producer(Product p){
this.p = p;
}




@Override
public void run() {
int i=0;
while(true){
synchronized(p){
                if(p.flag == false) {
       if(i%2==0){
      p.name = "苹果";
  
      p.price = 6.5;
       }else{
      p.name = "香蕉";
      p.price = 2.0;
       }
       System.out.println("生产者生产出了:"+p.name+"价格是:"+p.price);
           p.flag =true;
           
       i++;
       p.notifyAll();//唤醒消费者消费
                }else{
            //已经生产完毕,等待消费者先去消费
            try {
p.wait();//生产者等待
} catch (InterruptedException e) {
e.printStackTrace();
}
              }
}
}
}


}




//消费者
class Customer extends Thread{
Product p;
public Customer(Product p){
this.p = p;
}

@Override
public void run() {
while(true){
synchronized(p){
if(p.flag == true){//产品已经生产完毕
      System.out.println("消费者消费了:"+p.name+"价格:"+p.price);
      p.flag = false;
      p.notifyAll();//唤醒生产者生产
}else{
//产品还没有生产,应该等待生产者先生产
try {
p.wait();//消费者邓艾
} catch (InterruptedException e) {

e.printStackTrace();
}
}
}
}
}

}
public class Demo5 {


public static void main(String[] args) {
Product p = new Product();//产品
//创建生产者对象
Producer producer=new Producer(p);
//创建消费者对象
Customer customer = new Customer(p);
producer.start();
customer.start();


}


}



package cn.itcast.thread;
/*
 线程的停止:
 1.停止一个线程我们一般都会通过一个变量去控制的。
 2.如果需要停止一个等待状态下的线程,我们需要通过变量配合notify方法或者interrupt()来使用。
 
 interrupt()1.可以没有锁对象调用
            2.可以唤醒指定的等待线程对象
            3.把线程的等待状态强制清楚,被清楚状态的线程会接收到一个InterruptedException
 */


public class Demo6 extends Thread {
public Demo6(String name){
super (name);
}
boolean flag = true;




@Override
public synchronized void run() {
int i = 0;
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("接收到了异常啊");
}
System.out.println(Thread.currentThread().getName()+":"+i);
   i++;
}
}




public static void main(String[] args) {
Demo6 d = new Demo6("狗娃");
   d.setPriority(10);
d.start();

for(int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
//当主线程为80的时候停止狗娃线程
//d.interrupt();//interrupt方法根本无法停止线程
if(i == 80){
d.flag = false;
d.interrupt();//把线程的等待状态强制清楚,被清楚状态的线程会接收到一个InterruptedException
/*synchronized(d){
d.notify();
}
*/
}

}


}


}





package cn.itcast.thread;
/*
 
 守护线程(后台线程):在一个进程中只剩下了守护线程,那么守护线程也会死亡
 
 一个线程默认都不是守护线程
 
 
 */


public class Demo7 extends Thread{

public Demo7(String name){
super(name);
}




@Override
public void run() {
for (int i = 1;i<=100;i++){
System.out.println("更新包目前下载"+i+"%");

if(i==100){
System.out.println("更新包下载完毕,准备安装。");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}






public static void main(String[] args) {
Demo7 d = new Demo7("后台线程");

//System.out.println("是守护线程吗?"+d.isDaemon());//判断线程是否为守护线程
d.setDaemon(true);//setDaemon设置线程是否为守护线程,true为守护线程,false为非守护线程

d.start();

for (int i = 1;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}



}


}





package cn.itcast.thread;
/*
 join方法:加入
 
 
 
  */




//老妈
class Mom extends Thread{


@Override
public void run() {
System.out.println("妈妈洗菜");
System.out.println("妈妈切菜");
System.out.println("妈妈准备炒菜,发现没酱油了。。。");

//儿子去打酱油了
Son s= new Son();
s.start();
try {
s.join();//加入 。一个线程如果执行了join语句,那么就有新的线程加入,执行该语句的线程必须要让步给新加入的线程先完成任务,然后才能继续执行。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


System.out.println("妈妈继续炒菜");
System.out.println("全家一起吃饭");
}


}


class Son extends Thread{


@Override
public void run() {
System.out.println("儿子下楼。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

e.printStackTrace();
}
System.out.println("儿子一直往前走");
System.out.println("儿子打完酱油了");
System.out.println("上楼把酱油给老妈");
}

}
public class Demo8 {


public static void main(String[] args) {
Mom m = new Mom();
m.start();


}


}





原创粉丝点击