【Java】java多线程
线程基本概念
线程是什么?
一个线程就是一个程序内部的一条执行路径,一个进程可以包含多个进程。
当程序启动运行时,就自动产生了一个线程,主函数main就是在这个线程上运行的,当不再产生新的线程时,程序就是单线程,只有一条执行路径。
进程是什么?
计算机中的程序关于某数据集合上的一次运行活动。可以理解成每个独立运行的程序就是一个进程,进程也就是“正在运行的程序”。
线程和进程的区别:
每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,线程可以看成是轻量级的进程,同一线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程的切换开销小。
什么是多进程:
在操作系统中同时执行多个程序
什么是多线程:
在同一个应用程序中有多个执行路径,但是在一个时间点上,只用一个线程在该CPU 上运行。
多线程的创建和启动
创建多线程有两种方法:继承Thread类和实现Runnable 接口
使用Thread类创建多线程
Thread 类是java 中一个线程类,线程可以通过继承java.lang.Thread的类来实现。
java 程序在启动时由一个主方法main{}创建了一个线程,我们称之为主线程。
我们可以通过创建Thread的实例来创建线程,必须通过调用Thread 类的start方法启动一个线程,
public class A {
public static void main(String[] args) {
B b=new B();
b.start();
while(true)
{
System.out.println("main thread is running.");
}
}
}
class B extends Thread {
public void run()
{
while(true)
{ System.out.println(Thread.currentThread().getName()+" is running.");
}
}
}
thread 类有一个start方法,该方法为线程启动,会去执行继承Thread类的run 方法。
要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread类的子类。
一个thread类的对象就代表一个线程,而且只能代表一个线程
使用Runnable 接口创建多线程
Runnable接口有一个run()方法,用于定义线程运行体,所以我们只需要重写这个方法就可以。
public class A {
public static void main(String[] args) {
B b=new B();
Thread t=new Thread(b); //创建一个线程,b为Runnable 接口对象
//线程启动,会去调用run方法,不能直接调用run方法,那不是启动新线程,而是方法调用
t.start();
while(true)
{
System.out.println("main thread is running.");
}
}
}
class B implements Runnable {
public void run()
{
while(true)
{ System.out.println(Thread.currentThread().getName()+" is running.");
}
}
}
线程的状态控制:
当我们的线程被new出来的时候只是一个对象,当我们调用start 的方法时,就进入就绪状态,当被调度到cpu的时候才进入运行状态,在运行的过程中如果突发事件导致阻塞,则进入阻塞状态,阻塞解除之后进入就绪状态,线程只能从就绪态到运行状态。
线程控制的基本方法:
isAlive():判断线程是否还活着,即线程是否还未终止
getPriority():获得线程的优先级数值。
setPriority():设置线程的优先级数值。
Thread.sleep():当前线程睡眠指定毫秒数
join:合并某线程
yield:让出cpu,当前线程进入就绪队列等待调度。
wait() :当前线程进入对象的wait pool中
notify()/notifyAll():唤醒对象的wait pool中的一个/所有等待线程。
sleep:
public static void sleep(long millis) throws interruptedException
public class TestInterrupt{
public static void main(String[] args){
MyThread thread=new MyThread();
thread.start();
try{Thread.sleep(100000);}
catch(InterruptedException e){}
thread.interrupt(); //打断
}
}
class MyThread extends Thread{
}
线程同步:
多个线程之间访问同一份资源的时候,只能有一个线程访问该资源,其他线程都不可以对该资源进行访问,直到该线程结束, 其他线程才能访问该资源。
没有使用锁的代码:
public class TT implements Runnable{
int b=100;
public synchronized void m1() throws Exception{
b=1000;
Thread.sleep(5000);
System.out.println("b="+b);
}
public void m2() throws Exception{
Thread.sleep(2500);
b=2000;
}
public void run(){
try{
m1();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
TT tt=new TT();
Thread t=new Thread(tt);
t.start();
Thread.sleep(1000);
tt.m2();
}
}
当前程序有两个线程对象,一个主线程,一个t.start线程,当执行t.strat()时候,t线程会去执行m1,t1线程获得了这把锁,此时b=1000,其他线程不能再来执行这个方法,但是其他线程可以去执行别的方法,在t1睡眠5秒时,tt线程去执行m2 方法,此时b=2000,然后t线程再去打印b, 再去所有打印出来的b是2000。
假如给m2 方法也加上锁,如下
public class TT implements Runnable{
int b=100;
public synchronized void m1() throws Exception{
b=1000;
Thread.sleep(5000);
System.out.println("b="+b);
}
public synchronized void m2() throws Exception{
Thread.sleep(2500);
b=2000;
}
public void run(){
try{
m1();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
TT tt=new TT();
Thread t=new Thread(tt);
t.start();
Thread.sleep(1000);
tt.m2();
}
}
本程序有两个线程,首先是t调用m1方法,给对象加锁,此时tt不能再为该对象加锁,只能等待t执行完,才能对m2加锁,执行m2的方法,某一对象在某一时刻只能被一个线程加锁, synchronized 锁定当前对象,某一时刻只能锁定当前对象的一个方法,另外一个加锁的方法不能再去锁定当前对象。每一个对象只有一把锁,谁拿到这把锁谁就执行该方法,其他的对象不能拿到该对象的这把锁。
上一篇: 练习:序列化集合
下一篇: ThreadLocal内存泄漏原因