文章目录
进程和线程
1、进程:进程是指一个内存中运行的应用程序,每个进程都有独立的一块内存空间,即称为进程空间或者虚空间
2、线程:指进程中的一次执行流程,一个进程可以运行多个线程,线程没有自己的虚拟地址空间,与进程内其他线程共享分配资源;线程包含的内容:指令指针、栈、寄存器集合、私有数据区
线程创建方式
1、Thread类:可以对Thread类进行派生并覆盖run方法
(1)构造方法:
方法名 | 说明 |
---|---|
public Thread() | 分配一个新的线程对象 |
public Thread(String name) | 分配一个指定名字的新的线程对象 |
public Thread(Runnable target) | 分配一个带有指定目标新的线程对象 |
public Thread(Runable target,String name) | 分配一个带有指定目标新的线程对象并指定名字 |
(2)常用方法:
方法名 | 说明 |
---|---|
public String getName() | 获取当前线程名称 |
public void start() | 导致此线程开始执行,Java虚拟机调用此线程的run方法 |
public void run | 此线程要执行的任务在此处定义代码 |
pulic static void sleep(long mills) | 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行) |
public static Thread currentThread() | 返回当前正在执行的线程对象引用 |
3、实例代码:
public class MyThread extends Thread{
/** 利用继承中的特点 * 将线程名称传递 进行设置 */
public MyThread(String name){
super(name);
}
/** 重写run方法 * 定义线程要执行的代码 */
public void run(){
for (int i = 0; i < 20; i++) { //getName()方法 来自父亲
System.out.println(getName()+i);
}
}
}
public class Demo {
public static void main(String[] args) {
System.out.println("这里是main线程");
MyThread mt = new MyThread("小强"); mt.start();
//开启了一个新的线程
for (int i = 0; i < 20; i++) {
System.out.println("旺财:"+i);
}
}
}
2、Runnable接口
1、重写run方法即可创建线程
2、实例代码:
public class MyRunnable implements Runnable{
//Overridez注解方法重载了父类
@Override
public void run(){
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
public class Demo{
public static void main(String[] args){
//创建自定义类线程任务对象
MyRunnable m=new MyRunnable();
//创建线程对象
Thread=new Thread(m,"狗");
t.start();
for(int i=0;i<20;i++){
System.out.println("猫"+ i);
}
}
}
Thread和Runnable的区别
1、Thread不适合资源共享,Runnable接口可以实现资源共享
2、Runnable适合多个相同的程序代码的线程去共享一个资源、可以避免Java中单继承的局限性,增加程序的健壮性,实现解耦操作,代码可以被多个线程共享;线程池只能放入实现Runnable类线程
3、匿名内部类方式实现线程的创建
1、使用匿名内部类的方式实现Runable接口,重写Runnable接口中的run方法
2、实例代码:
public class Nameinner{
public static void main (String[] args){
Runnable r=new new Runnable(){
public void run(){
for(int i=0;i<20;i++){
System.out.println("张三"+i);
}
} ;
new Thread(r).start();
for(int i=0;i<20:i++){
System.out.println("李四"+i);
}
}
}
线程安全
1、定义:多个线程同时运行,而同时运行同个代码,程序每次运行结果和单线程运行的结果是一样的,而且其他变量和预期值是一样的,称为线程安全。线程安全问题都是由全局变量及静态变量引起的,若每个线程中对全局变量、静态变量只有读操作而无写操作,一般这个全局变量是线程安全的,如有多个线程同时执行写操作,需要考虑线程同步,否则可能影响线程安全。
线程同步
1、当多线程访问同一个资源的且有写操作的时候,容易出现线程安全问题。为了解决该问题Java提供了同步机制(synchronized)
2、完成同步的三种方式:
(1)同步代码块
(2)同步方法
(3)锁机制
同步代码块
1、synchronized关键字可以用于方法中的区块中,来表示只对这块的资源实现互斥访问。
2、格式:
synchronized(同步锁){
需要同步的代码块
}
3、同步锁:对象的同步锁为一种概念,可以想象在对象上标记了一个锁,锁对象可以是任意类型,多个线程对象要使用同一把锁
4、实例代码:
public class Ticket implements Runnable{
private int ticket = 100;
Object lock = new Object();
/** 执行卖票操作 */
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){ synchronized (lock) {
if(ticket>0){
//有票 可以卖 //出票操作 //使用sleep模拟一下出票时间
try {Thread.sleep(50); } catch (InterruptedException e) {
// TODO Auto‐generated
catch block e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket--);
}
}
}
}
}
同步方法
1、同步方法使用synchronized修饰的方法,就是同步方法,保证A线程在执行时,其它线程只能处于等待
2、格式:
public synchronized void method(){
可能会产生线程安全问题的代码
}
3、实例代码:
public class Ticket implements Runnable{
private int ticket = 100;
/** 执行卖票操作 */
@Override
public void run() {
//每个窗口卖票的操作 //窗口 永远开启
while(true){ sellTicket();
}
}
/** 锁对象 是 谁调用这个方法 就是谁 * 隐含 锁对象 就是 this **/
public synchronized void sellTicket(){ if(ticket>0){
//有票 可以卖 //出票操作 //使用sleep模拟一下出票时间
try {Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐);
}
}
}
Lock锁
1、Lock锁又称为同步锁
2、方法:
(1)public void lock(); //加同步锁
(2)public void unlock(); //释放同步锁
3、实例代码:
public class Ticket implements Runnable{
private int ticket = 100;
Lock lock = new ReentrantLock();
/** 执行卖票操作 */
@Override
public void run() {
//每个窗口卖票的操作 //窗口 永远开启
while(true){
lock.lock(); if(ticket>0){
//有票 可以卖 //出票操作 //使用sleep模拟一下出票时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace(); }
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐); }lock.unlock();
}
}
}
线程状态
1、线程状态转换图
2、线程状态
(1)线程状态分为五种,分别是,新建、就绪态、运行态、阻塞态、死亡态,而阻塞态分三种:等待阻塞、同步阻塞、其它阻塞
3、线程死锁
(1)两个线程都被阻塞,每个线程在等待另一个线程时会发生死锁