一、相关概念
1.并行与并发
并发:指两个或多个事件在同一个时间段发生(交替执行)
并行:指两个或多个事件在同一时刻发生(同时执行)
2. 多线程与多进程
多线程:在一个程序中同时运行多个任务
多进程:在操作系统中能同时运行多个任务(程序)
3. 线程和进程的区别
- 进程是运行中的应用程序,拥有自己独立的内存空间和资源
- 一个进程可以有一个或多个线程组成,且至少有一个线程称为主线程
- 线程是最小的处理单位,多个线程共享一块内存和资源
- 当一个线程改变了所属进程的变量时,其它线程下次访问该变量时得到这种改变
4. 线程的优点
- 充分利用CPU资源
- 简化编程模型
- 简化异步事件处理
- 使GUI更有效率
- 节约成本
5. 主线程
执行main方法的线程
package com.hyg.Tread;
/**
* 主线程,main方法开始执行
* 从上到下
* @author 15332
*
*/
public class MainTreadDemo {
public static void main(String[] args){
Person s1 = new Person("张三");
//test
s1.run();
Person s2 = new Person("李四");
s2.run();
}
}
package com.hyg.Tread;
public class Person {
private String name;
public void run(){
for(int i = 0;i<21;i++){
System.out.println(name+"-->"+i);
}
}
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
二、创建线程
1. 使用Thread类
java.lang.Tread类:是描述线程的类,我们想要实现多线程,就必须继承Tread类
①步骤
- 创建一个Tread类的子类,开启
- 在Ttead的子类中从写Tread的run方法,设置线程任务
- 创建子类对象
- 调用Tread类中start方法,开启新的线程,执行run方法
② 案例
package com.hyg.Tread;
/**
* 继承Tread类
* 重写run方法
* @author 15332
*
*/
public class MyTread extends Thread {
@Override
public void run() {
for(int i =0 ;i<20 ; i++){
System.out.println("run:"+i);
}
}
}
package com.hyg.Tread;
/**
* 创建Tread子类对象,调用start方法启动线程,调用run犯法
* @author 15332
*
*/
public class MyTreadDemo {
public static void main(String[] args) {
MyTread myTread = new MyTread();
myTread.start();
for(int i =0 ; i<20 ; i++){
System.out.println("main:"+i);
}
}
}
③ Thread的方法
2. 使用Runnable接口
①步骤
- 创建一个Runnable接口的实现类
- 在是实现类中重写Runnable接口的run方法,设置线程任务
- 创建一个Runnable接口的实现类对象
- 创建Thread类对象,构造方法中传递Runnable接口的实现类对象
- 调用Thread类的start方法,开启新线程,执行run方法
② 案例
package com.hyg.Runnable;
/**
* 创建Runnable接口的实现类,并重写run方法
* @author 15332
*
*/
public class RunnableImpl implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i =0 ;i<20 ; i++){
System.out.println("run:"+i);
}
}
}
package com.hyg.Runnable;
/**
* 创建Runnable接口实现类对象
* 创建Thread对象,在构造方法中传入Runnable接口实现类对象
* 调用Thread对象的start方法
* @author 15332
*
*/
public class RunnableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
RunnableImpl run = new RunnableImpl();
Thread t = new Thread(run);
t.start();
for(int i =0 ;i<20 ; i++){
System.out.println("main:"+i);
}
}
}
③ 好处
- 避免了单继承的局限性
- 增强了程序的扩展性,降低了程序的耦合性()解耦
实现Runnable接口的方式,把设置线程任务和开启线程进行了分离(解耦)
实现类中,重写run方法用来设置线程任务
创建Thread类对象,调用start方法用来开启新线程
3. 使用匿名内部类创建线程
线程的父类是Thread
package com.hyg.anonymous;
/**
* 使用匿名内部类实现Thread创建线程
* @author 15332
*/
public class AnonymousThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
for(int i =0 ;i<20 ; i++){
System.out.println("run:"+i);
}
}
}.start();
}
}
线程的父类是Runnable
package com.hyg.anonymous;
import com.hyg.Runnable.RunnableImpl;
/**
* 使用匿名内部类实现Runnable接口的实现类创建线程
* @author 15332
*
*/
public class AnonymousRunnableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
* 方式一
*/
Runnable r = new RunnableImpl(){
@Override
public void run() {
for(int i =0 ;i<20 ; i++){
System.out.println("Run:"+i);
}
}
};
new Thread(r).start();
/*
* 方式二
*/
new Thread(new RunnableImpl(){
@Override
public void run() {
for(int i =0 ;i<20 ; i++){
System.out.println("Run1:"+i);
}
}
}).start();
};
}
三、 线程同步
为了解决线程安全问题
同步代码块
- 通过代码块中的锁对象,可以使用任意的对象
- 但是必须保证多个线程使用的锁对象是同一个
- 锁对象的作用
把同步代码块锁住,只让一个线程在同步代码块中执行
synchronized(同步锁){
需要同步操作的代码
}
同步方法
- 把访问了共享数据的代码抽取出来,放在一个方法上
- 在方法中添加synchronized 修饰符
- 同步方法会把方法内部的代码锁住,只让一个线程执行
- 同步方法的锁对象就是this
public synchronized void method(){
可能产生线程安全问题的代码块
}