进程
具有一定独立功能的程序关于某个数据集合上的一次运行活动;
线程
线程是最小的执行单元,而进程由至少一个线程组成。
关系
进程和线程的关系:
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)CPU分给线程,即真正在CPU上运行的是线程。
多线程的好处
- 效率高
- 多个线程之间互不影响
多线程的调度
- 分时调度(轮流使用cpu)
- 抢占式调度(享有优先级,优先级高的先使用cpu)
创建多线程
- 继承Thread类并重写run⽅法;
- 实现Runnable接⼝的run⽅法;
Tread常用方法
- 获得名称
public class MyThread extends Thread {
@Override
public void run() {
// 获取线程方法的名字 方法一
// String threadName = super.getName();
// System.out.println(threadName);
// 方法二 使用静态方法currentThread
Thread thread = currentThread();
System.out.println(thread);
String name = thread.getName();
System.out.println(name);
}
}
// 测试
public class MyThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
new MyThread().start();
new MyThread().start();
new MyThread().start();
//main 线程名
System.out.println("主线程"+Thread.currentThread().getName());
}
}
- 设置线程名称
<!--方法一:调用父类的构造方法可以设置-->
public class MyThread extends Thread {
public MyThread(String str) {
super(str);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
<!--方法二:-->
public class MyThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setName("zidingyi");
myThread.start();
}
}
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
- sleep 静态方法可以直接使用类名.方法名调用
Runnable
public class RunnableImpl implements Runnable{
/** 实现Runnable接口方式
* 1.创建Runnable接口实现类,Runnable中只有一个run方法
* 2.在实现类中重写run方法
* 3.创建Thread对象,在构造方法中传入Runnable实现类对象
* 4.调用Thread的start方法,开启新的线程
*
*/
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName());
}
}
}
--------------------------------------------
public class MyRunnable {
public static void main(String[] args) {
RunnableImpl runnable = new RunnableImpl();
new Thread(runnable).start();
//主线程
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName());
}
}
}
创建新线程的两种方式的区别
实现Runnable创建多线程程序的好处
- 避免了单继承的局限性,一个类只能继承一个类,继承了Thread类就不能继承其他类
- 增强了程序的扩展性,降低了程序的耦合性(解耦),实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离
匿名内部类实现多线程
public class InnerClassTest {
public static void main(String[] args) {
//第一种方式
new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-----------方式一");
}
}.start();
// 第二种方式
Runnable runnable2 = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "-----------方式二");
}
};
new Thread(runnable2).start();
// 第三种方式:简化了第二种方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "-----------方式三");
}
}).start();
}
}
线程不安全
解决方式
- 设置同步锁(同步代码块)创建锁对象使用synchronized包括代码块 代价:降低了程序的效率
public class SaleTicketsImpl implements Runnable{
private int ticket=100;
Object obj =new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket);
ticket--;
}
}
}
}
}
public class Test {
public static void main(String[] args) {
SaleTicketsImpl saleTickets = new SaleTicketsImpl();
Thread thread1 = new Thread(saleTickets);
Thread thread2 = new Thread(saleTickets);
Thread thread3= new Thread(saleTickets);
thread1.start();
thread2.start();
thread3.start();
}
}
- 同步方法 synchronized修饰方法,方法中放访问共享数据
public class SaleTicketsImpl implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
payTickets();
}
}
public synchronized void payTickets() {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket);
ticket--;
}
}
}
- Lock锁 可以获取锁和释放锁
1.在成员位置创建一个ReentrantLock对象
2.在可能出现线程安全的代码前调用Lock接口中的方法获取锁
2.在可能出现线程安全的代码前调用Lock接口中的方法释放锁
public class SaleTicketsImpl implements Runnable {
private int ticket = 100;
/*1.创建Lock对象*/
Lock l1 = new ReentrantLock();
@Override
public void run() {
while (true) {
// 2.获取锁
l1.lock();
try {
if (ticket > 0) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket);
ticket--;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//3.释放锁
l1.unlock();
}
}
}
}