`
_kudy
  • 浏览: 15094 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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() 等待  唤醒(下一个的概念)
但是前提是同步函数里面使用.并且是同一把锁.注意锁的概念.程序要多敲-->后面理解毕竟不是很好.

 

分享到:
评论

相关推荐

    javaSE代码实例

    第16章 多线程——Java中的并发协作 343 16.1 线程的基本知识 343 16.1.1 多线程编程的意义 343 16.1.2 定义自己的线程 344 16.1.3 创建线程对象 345 16.1.4 启动线程 347 16.1.5 同时使用多个线程 ...

    狂神笔记,b站狂神说课程笔记大全(最新)

    11、JavaSE:多线程 12、JavaSE:网络编程 13、JavaSE:Gui编程 14、JavaSE:注解和反射 15、MySQL和JDBC 16、前端:Html5 17、前端:CSS3 18、前端:JavaScript、jQuery 19、JavaWeb 20、MyBatis 21、Spring 22、...

    狂神说上课笔记未删减 Java基础到技术升级

    11、JavaSE:多线程 12、JavaSE:网络编程 13、JavaSE:Gui编程 14、JavaSE:注解和反射 15、MySQL和JDBC 16、前端:Html5 17、前端:CSS3 18、前端:JavaScript、jQuery 19、JavaWeb 20、MyBatis 21、...

    狂神说Java 笔记,java入门,docker ,spring 全家桶,redis , mysql , vue , javascript ,htm5, css

    11、JavaSE:多线程.pdf 12、JavaSE:网络编程.pdf 13、JavaSE:Gui编程.pdf 14、JavaSE:注解和反射.pdf 15、MySQL和JDBC.pdf 16、前端:Html5.pdf 17、前端:CSS3.pdf 18、前端:JavaScript、jQuery.pdf ...

    传智播客的android开发源代码

    31_多线程断点下载器.avi 所在项目:MulThreadDownloader 32_文件断点上传器.avi 所在项目:videoUpload & javaSE应用:socket 33_为应用添加多个Activity与参数传递.avi 所在项目:MulActivity 34_Activity的启动...

    source.zip

    31_多线程断点下载器.avi 所在项目:MulThreadDownloader 32_文件断点上传器.avi 所在项目:videoUpload & javaSE应用:socket 33_为应用添加多个Activity与参数传递.avi 所在项目:MulActivity 34_Activity的启动...

    8天快速掌握Android教程源码

    31_多线程断点下载器.avi 所在项目:MulThreadDownloader 32_文件断点上传器.avi 所在项目:videoUpload & javaSE应用:socket 33_为应用添加多个Activity与参数传递.avi 所在项目:MulActivity 34_Activity的启动...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    第12章多线程开发 第13章反射技术 第14章实验指导3 下篇UML 第15章UML入门 第16章用例图 第17章类图和对象图 第18章实验指导4 第19章顺序图、协作图、状态图和活动图 第20章包图、构件图和部署图 第21...

    java基础案例与开发详解案例源码全

    12.1.5 为什么需要多线程309 12.1.6 线程分类309 12.2 线程的生命周期309 12.2.1 线程的状态及转换310 12.2.2 线程睡眠311 12.2.3 线程让步313 12.2.4 线程的加入313 12.3 线程的调度和优先级314 12.4 线程的同步315...

    java版坦克大战源码-tankwar:坦克大战,java版联机对战游戏

    多线程, NIO,netty等基础知识。真正做到理解实战项目的开发过程。 代码模块介绍 Tank2019V2 父项目 --lib 存放jar包 --out 反编译包 --src 源码包 --audio 音频 --com 源码 --chainofresponsibility 实体间...

    Java学习笔记-个人整理的

    {8}多线程}{121}{chapter.8} {8.1}线程的常用属性与方法}{121}{section.8.1} {8.2}后台线程}{123}{section.8.2} {8.3}创建线程的两种方法}{123}{section.8.3} {8.4}Runnable}{123}{section.8.4} {8.5}Sleep...

Global site tag (gtag.js) - Google Analytics