javase_19(多线程)

进程:

进程是具有一定独立功能的程序关于某个数据集合上的一次运动.

 

线程:

线程是进程里面的一个实体,CPU调度或分派的基本单位

 

进程与线程之间的区别:

总而言之,一个进程里面可以有多个线程,但是一个进程至少有一个线程

 

多线程存在的意义:

程序允许有多个线程并发,提供程序的运行的效率   

 

线程的创建方式:

new Thread().start();

 

 

 

 

 

 

多线程的应用:

Sun公司为我们提供了Thread类来实现线程

通过new Thread()来创建一个线程对象.

定义一个类继承Thread,子类就有了线程的功能

创建Thread类的子类的对象,也可以创建一个线程.

 

线程的启用:

Thread类定义了run()方法,用于启动当前的线程

在启用当前的线程的时候,虚拟机会自动调用于run()方法

 

线程的其他方法:

sleep:使线程进入到睡眠的状态,需要唤醒的时间,会抛异常

setDaemon:将当前的线程设置为一个后台的线程,但主线程结束,它也会跟着结束

Join:合并一个线程,会抛出异常-->合并进来,join被谁调用,谁就执行.

currentThread:获取当前运行的线程.

 

 

 

package com.javami.kudy.DemoThread;

public class ThreadTest {
    
    public static void main(String[]args)
    {
        int num = 0;
        MyThread mt = new MyThread();
        //为当前的线程起名字
        mt.setName("kudy-0");
        mt.setDaemon(true); //设置为后台线程,但主线程执行完毕.后台线程也会跟着退出
        mt.start();
        //一个进程至少有一个主线程
        while(true)    
        {
            if(num++>10)
                break;
            try{mt.join();}catch(Exception e){e.printStackTrace();}
            try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}
            System.out.println(Thread.currentThread().getName()+"Main()");
        }
        
    }
}


class MyThread extends Thread
{
    @Override
    public void run()
    {
        while(true)
        {
            //获取当前线程
            try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}
            System.out.println(Thread.currentThread().getName()+" run()");
        }
    }
}

 

创建线程的方式二:

 

实现Runnable接口

子类覆盖父类中的run()犯法

通过Thread类创建线程,并且实现了Runnable接口中的子类

对象作为参数传递给Thread类型类的构造函数

 

这样做有什么好处:

线程开了,并且只是处理一个对象.用到了组合模式

 

为什么需要用到同步代码块或者同步函数:

 

由于程序在执行的时候,会出现线程不安全的问题,所以我们需要用到同步函数或者同步代码块.

导致线程不安全的注意问题:

 

1.多个线程随机访问延时

2.线程随机性

 

同步代码块:

Synchronized(对象)  //锁旗标 0开 1

{

需要同步的代码;

}

同步代码可以解决安全的问题根本原因在于对象上面,该对象如同锁的功能.

 

同步函数:

在函数上面加上synchronized修饰即可.

Public synchronized void sale()

{

//同步代码块使用的锁是this这个锁

}

死锁:

发生在相互调用的情况下,一个同步函数里要用到和同步代码块相同的锁,同步代码块又去调用函数,就用到函数的锁,两者都会锁死,发生死锁的问题.

 

package com.javami.kudy.DemoThread;
 
 public class TicketsSale {
 
     /**
      * @param args
      * 多线程售票:同时开启4个线程售票
      * 
      * 线程安全问题在理想的状态下,不容易出现,但一旦出现就是对软件的影响是非常之大
      * Thread-1  -1
        Thread-0  0
        Thread-3  1
        ----↓
        同步代码块
        与同步函数:
        
      */
     public static void main(String[] args) {
         SaleThread st = new SaleThread();
         
         //4个进程产生
         new Thread(st).start();
         new Thread(st).start();
         new Thread(st).start();
         new Thread(st).start();
     }
 }
 
 class SaleThread implements Runnable
 {
     String lock = ""; //锁期标
     private int tickets = 10; //10张车票
     @Override
     public void run()
     {
         
         while(true)  // 0 1 2 3 等待我执行完毕别的线程才去抢
         {
             synchronized(lock)
             {
             if(tickets<1)
                 break;
             try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}
             System.out.println(Thread.currentThread().getName()+"  "+tickets--);
             }
         }
     }
 }

 

同步的特点:

 

1.同步需要两个或者两个以上的线程.

2.多个线程使用的是同一把锁

3.为满足这两个条件,不能称其为同步.

 

同步的弊端:

 

1.当线程相当多的时候,因为每个线程都会去判断同步上的锁.这是很消耗资源的,判断该锁是否被锁上.如果锁上.需要等锁上的开了才可以互相抢进去.

无形中可以减低了程序运行的效率.

 

package com.javami.kudy.DemoThread;
 
 public class TicketsSale1 {
     /*
      * 使用同步函数与同步代码块来实现4个线程
      */
     public static void main(String[]args)
     {
         SaleThread1 st = new SaleThread1();
         new Thread(st).start();
         new Thread(st).start();
         st.lock = "ok";
         try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}
         new Thread(st).start();
         new Thread(st).start();
     }
 }
 
 class SaleThread1 implements Runnable
 {
     String lock = " ";
     private int num = 100;
     public void run()
     {
         if(lock.equals("ok"))
         {
             while(true)
             {
                 sale();
             }
         }else
         {
             while(true)
             {
                 synchronized (this) {
                     if(num<1)
                         return;
                     System.out.println(Thread.currentThread().getName()+"else"+num--);
                 }
             }
         }
     }
     
     
     private synchronized void sale() {
             if(num<1)
                 return;
             System.out.println(Thread.currentThread().getName()+"if"+num--);
     }
 }

  

线程间的通信:

 

两个线程之间可以相互的通信

一个线程可以通过wait方法等待,这时CPU会让给别程

通过进行等待的线程需要其他线程调用notify()方法唤醒.

package com.javami.kudy.DemoThread;
 
 /*
  * 通信必须要在同步函数里面去解决的
  */
 class SQL
 {
     public String name;
     public String sex;
     public boolean  b = false;
 }
 class DBA implements Runnable
 {
     SQL sql ;
     public DBA(SQL sql)
     {
         this.sql = sql;
     }
     public void run()
     {
         int num = 0;
         while(true)
         {
             synchronized (sql) {
             if(sql.b) //为真.我等待,让给别的进程~
                 try{sql.wait();}catch (Exception e) {e.printStackTrace();}
             if(num ==0)
             {
                 sql.name = "小细";
                 sql.sex = "男";
             }else
             {
                 sql.name = "美怡";
                 sql.sex = "女";
             }
                 num = (num+1)%2;  //实现了来回打印
                 sql.b = true;
                 sql.notify(); //等待完毕需要把你唤醒~
             }
         }
     }
 }
 
 /*
  * 编码员
  */
 class Coder implements Runnable
 {
     SQL sql ;
     public Coder(SQL sql)
     {
         this.sql = sql;
     }
     public void run()
     {
         while(true)
         {
             synchronized (sql) {
                 if(!sql.b) //如果为假-->我等待
                 try{sql.wait();}catch(Exception e){e.printStackTrace();}
                 System.out.print(sql.name+" ");
                 System.out.println(sql.sex+" ");
                 sql.b = false; //标记为假~~并且把这个进程唤醒
                 sql.notify();
             }
         }
     }
 }
 public class SqlThread {
 
     /**
      * 模仿数据库的操作,实现边读取,边打印
      */
     public static void main(String[] args) {
             SQL sql = new SQL();
             DBA dba = new DBA(sql);
             Coder cr = new Coder(sql);
             new Thread(dba).start();  //一个线程交换位置
             new Thread(cr).start(); //另外一个线程马上就打印出来
     }
 
 }

 

思考:

wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?

wait(),sleep()有什么区别?

Wait():假设我同步代码块抢到啦.我执行wait()方法,就会让该线程等待.让别的线程执行.

Notiyf():唤醒等待中的线程-->下一个

notiyfyAll():  唤醒在此对象监视器上等待的所有线程。

Sleep():这个是去睡觉去啦~~~不需要你唤醒的,这家伙是自然醒.

使用1.5lockcondition解决存和取之间的通信问题

 

 

package com.javami.kudy.DemoThread;

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

/*
 * 锁必须要一样,才能称得上同步
 */
class MyArray1
{
	private int[] arr = new int[10];
	private int savePos = 0;
	private int getPos = 0;
	private Lock lock = new ReentrantLock(); //创建一个锁
	private int count = 0;
	private Condition isFull = lock.newCondition(); //返回一个通信对象
	private Condition isEmpty = lock.newCondition();//返回的地址一样
	
	public void add(int num) throws InterruptedException
	{
		//但我执行慢的时候.我这个锁会开.开的时候.一看count==10等待..又抢,如果是你.你就等待.否则就是get  但是执行完毕一定要把当前的线程唤醒
		try
		{
			lock.lock();//开锁
			while(count==10)
				isFull.await();//if等于10了,你就必须等待
			if(savePos==10)
				savePos = 0;
			arr[savePos++] = num;
			count++;
		}finally
		{
			isEmpty.signal();//唤醒
			lock.unlock();
		}
	}
	
	public int get() throws InterruptedException
	{
		try
		{
			lock.lock(); //开锁
			while(count==0)
				isEmpty.await();//等待
			if(getPos==10)
				getPos = 0;
			count--; //不-- ~?  数组问题
			return arr[getPos++];
		}finally
		{
			isFull.signal();//等待的哥们.我去叫醒你啦~~
			lock.unlock();//开锁
		}
	}
}
public class ArrayThreadDemo {
	static int num = 1;
	public static void main(String[]args)
	{
		final MyArray1 ma = new MyArray1();
		new Thread(new Runnable(){
			@Override
			public void run() {
				for(int i=0; i<30; i++)
				{
					try {
						ma.add(num++);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
		}).start();
		new Thread(new Runnable(){

			@Override
			public void run() {
				for(int i=0; i<30; i++)
				{
					try {
						System.out.println(ma.get());
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
		}).start();
		new Thread(new Runnable(){
			@Override
			public void run() {
				for(int i=0; i<30; i++)
				{
					try {
						ma.add(num++);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
		}).start();
		new Thread(new Runnable(){

			@Override
			public void run() {
				for(int i=0; i<30; i++)
				{
					try {
						System.out.println(ma.get());
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
		}).start();

	}
}


今天的知识点回顾:

总体来说:但是今天的精神很好..最后面的一道题目要多加练习
第二: 同步函数是:必须执行完才执行到你,但是同步完毕后不保证以后线程(抢)线程的情况.所以我们又用到 wait() 等待  唤醒(下一个的概念)
但是前提是同步函数里面使用.并且是同一把锁.注意锁的概念.程序要多敲-->后面理解毕竟不是很好.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值