一:进程与线程的区别:

1.线程:程序中单独顺序的控制流,线程本身依靠程序进行运行,线程   是程序中的顺序控制流,只能使用分配给程序的资源和环境。

2.进程:执行中的程序一个程序可以包含一个或多个线程一个进程自少     要包含一个线程。

3.单线程:程序中只存在一个线程,实际上主方法就是一个主线程。

4.多线程:多线程是在一个程序(进程)中运行多个任务(线程),多线程的目的是更好的使用CPU资源。

5、线程运行的原理

  • 分时调度

所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。

  • 抢占式调度

优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。


 二、并行与并发

  • 并行:多个CPU实例或者多台机器同时执行一段处理逻辑,是真正的同时运行。
  • 并发:通过CPU调度算法,让用户看上去在同时执行,实际上从CPU操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用资源往往产生瓶颈,我们会用TPS(Transactions Per Second,每秒传输的事物处理个数)或者QPS(Query Per Second,每秒查询率)来反映这个系统的处理能力。

从下面的图例可以看出并行(Parallel)与并发(Concurrent)的区别。简单来说,并行就是多个线程同时访问多个对象,可以理解为多个用户同时使用多个服务资源。并发就是多个线程同时访问一个对象,可以理解为多个用户同时使用同一个服务资源。

java 单线程 多线程 线程锁实例 java单线程和多线程的区别_java


三、线程的实现

<1>在Java中,线程的实现有2种方法:

  • 继承Thread类
  • 实现Runnable接口

1、继承Thread 类, Thread类是在Java.lang包中定义的,一个类只要继承了Thread类,此类就称为多线程实现类,继承Thread类必须重写run()方法。

    定义的格式:

class 类名称 extends Thread{//继承Thread类
      public void run(){//覆写Thread类中的run()方法,此方法是线程的主体
            //线程主体
      }
 }

2、实现Runnable接口 

定义格式:

class 类名称 implements Runnable{
    属性……;
    方法……;
    public void run(){//覆写Runnable中的run()方法
        //线程主体
    }
}

<2>线程的启动方法

  • 要正确的启动线程,是不能直接调用run()方法的,而应该调用从Thread类中继承而来的start()方法。
class MyThread extends Thread{
	private String name;
	public MyThread(String name){
		this.name=name;
	}
	public void run(){
		for(int i=0;i<10;i++){
			System.out.println("name"+"运行,i="+i);
		}
	}
}

public class ThreadDemo{
	public static void main(String args[]){
		MyThread mt1=new MyThread("线程A");
		MyThread mt2=new MyThread("线程B");
		mt1.start();//启动多线程
		mt2.start();//启动多线程
	}
}

四、线程的状态(生命周期)

  1. 线程共有5种状态
  • 新建(New)状态:当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值。
  • 就绪(Runnable)状态:当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待cpu调度运行。
  • 运行(Running)状态:如果处于就绪状态的线程获得了CPU资源,开始执行run()方法的线程执行体,则该线程处于运行状态。
  • 阻塞(Blocked)状态:当处于运行状态的线程失去所占用资源之后,便进入阻塞状态。
  • 死亡(Dead)状态:线程被销毁。

java 单线程 多线程 线程锁实例 java单线程和多线程的区别_java 单线程 多线程 线程锁实例_02

  • 解释:yield()礼让

各种状态一目了然,值得一提的是"blocked"这个状态;线程在Running的过程中可能会遇到阻塞(Blocked)情况

  1. 调用join()和sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待JVM的调度。
  2. 调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),释放同步锁使线程回到可运行状态(Runnable)。
  3. 对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。
  4. 此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。

 五、线程的常用方法

1.取得线程名字

    getName()

2.取得当前线程对象

    currentThread()

3.判断线程是否启动

    isAlive()

4.线程的强行运行

    join()

5.线程的休眠

    sleep()

6.中断线程,当一个线程运行时另一个线程可以直接通过interrupt()方法中断其运行。

interrupt()


六、线程的优先级别

    1-MIN_PRIORITY

    10-MAX_PRIORITY

    5-NORM_PRIORITY

    如果什么都不设置默认值是5


七、同步与死锁

  • 同步,即两个或两个以上的线程需要共享对同一对数据的存取。

什么时候需要使用同步:在资源共享的时候需要

1.同步代码块

    在代码块上加"synchronized"关键字,则此代码块就称为同步代码块。

2.同步代码块格式:

synchronized(同步对象){
            需要同步的代码块;
}

3.同步方法:

    除了代码块可以同步,方法也是可以同步的

4.方法同步格式:

 

synchronized void 方法名称(){}

 

5.死锁:所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

比如:大学生找工作要找高薪的而企业要有经验才给高薪,如果双方标准都不降低就无法继

一和二代码:
代码一run方法:
package Java线程;
public class MyThread extends Thread {
    private String name;
    //创建构造方法进行传参
    public MyThread(String name){
        this.name=name;
    }
    //重写Run方法
    public void run(){
        //为了能看到用for循环做打印
        for(int i=0;i<1000;i++){
            System.out.println(name+":"+i);
        }
        //super.run();
    }
}
代码一run方法:
package Java线程;
//调用线程的主方法
public class ThreadDemo{
    public static void main(String [] args){
        //实例化线程A B启动线程
        MyThread t1=new MyThread("线程A:");
        MyThread t2=new MyThread("线程B:");
        //线程的启动是通过start()方法启动的
        t1.start();
        t2.start();

    }
}

代码二:Runnable接口
package 线程2;

//第二种方法通过实现Runnable接口来实现线程
public class MyRunnable implements Runnable{
    private String name;

    //构造方法传递参数标识当前线程
    public MyRunnable(String name){
        this.name=name;
    }

    //Runnable接口也要重写run方法
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println(name+":"+i);

        }

    }

}
代码二:runnable接口
package 线程2;

public class ThreadDemo2 {

    public static void main(String[] args) {
        //实现MyRunnable
        MyRunnable r1=new MyRunnable("线程A:");//A是一个name 标识当前的线程
        MyRunnable r2=new MyRunnable("线程B:");
        //runnable 接口不存在启动方法要通过线程启动
        Thread t1=new Thread(r1);//r1 r2为传递进来的Runnable 对象
        Thread t2=new Thread(r2);
        t1.start();
        t2.start();
    }

}

代码三同步与死锁:
package Java线程;

//线程的同步与死锁

class MyThreadDemo implements Runnable{

    private int ticket=5;
    public void run() {
        for(int i=0;i<10;i++){

            //调用tell方法
            tell();
            //为了资源能够共享使用线程同步(第一种方法)
            /*synchronized (this) {
                if(ticket>0){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("车票:"+ticket--);
                */
                }

            }
            //第二种使用线程同步方法来实现线程同步实现资源共享
            public  synchronized void tell(){
                if(ticket>0){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("车票:"+ticket--);
        }
    }

}


public class ThreadDemo05 {
    //主方法
    public static void main(String[] args) {
        MyThreadDemo m=new MyThreadDemo();
        Thread t1=new Thread(m);
        Thread t2=new Thread(m);
        Thread t3=new Thread(m);
        t1.start();
        t2.start();
        t3.start();
    }

}