引言
人类本质是懒惰的,要克服这种本性,‘奖励’再合适不过;
知识点总结
多线程
基本概念
1.并发与并行
并发是指一个cpu同时执行多个任务,执行方式是【反复横跳.jpg】,只是切换速度很快;
比如罗志祥的多人运动,罗志祥一个人做多件事;(🐶)
并行是指多个cpu执行多个任务,比如考试的时候多人在同一时间段做多份卷子;
2.进程与线程
进程是指一个程序执行一次的全部过程,是动态的;从产生到存在,最后消亡。
线程线程是进程中的一个执行单元;是一个进程中的众多执行路径之一。
多线程的内存原理
多线程的原理就是每一次的start()方法都会开辟出一个新的栈空间;所以线程之间是互不影响的;CPU每一时刻在其中根据选择一个线程执行。
选择某一线程的频率取决于线程的优先级。
多线程的创建方法
1.创建Thread的子类
类名 MyThread.java
是Thread的子类
-------------------
public class MyThread extends Thread{
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println("线程1 "+i);
}
}
}
=======================
类名 Demo01.java
---------------------
public class Demo01 {
public static void main(String[] args) {
Demo01Thread my1=new MyThread();
//开辟一个栈空间
my1.start();
}
}
2.Thread类的常用方法
public class Demo02 {
public static void main(String[] args) {
Thread tr=new Thread(){
public void run(){
//需要重写run()方法,说明线程任务
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(100);
//sleep()方法会抛出异常,需要处理产生的异常;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" "+i);
/*
currentThread()方法获取正在执行的线程;
getName()获取线程的名字;
*/
}
}
};
tr.start();
//开始执行线程
}
}
通过Runnable的实现类创建线程
实现步骤
- 创建Runnable的实现类
- 实现类重写run()方法
- 创建实现类的对象
- 将此类作为参数,构造Thread对象
- 通过Thread对象调用start()方法
用Runnable的好处
实现了线程任务与线程开启过程的相互分离,有利于降低程序的耦合性。
Runnable的实现类
Runnableimpl.java
------------------
public class Runableimpl implements Runnable{
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
=========================
创建实现类对象
Demo02Runnable.jav
-------------------------
public class Demo02Runnable {
public static void main(String[] args) {
Runnable ra1=new Runableimpl();
Thread tr1=new Thread(ra1);
tr1.start();
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
匿名内部类创建线程
遇到的时候能看懂即可,无要求。
public class Demo03 {
public static void main(String[] args) {
new Thread(){
public void run(){
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}.start();
//=====================================================
Runnable ru=new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
};
Thread th=new Thread(ru);
th.start();
//================================================
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}).start();
}
}
线程安全问题
产生原因
多线程访问一个共享数据区域;
下面是模拟三个窗口同时卖火车票的例子,其中100张票就是一个共享的数据区域;
public class Demo04Safe {
/*
线程创建过程
1.实现接口
2.重写方法
3. *.start()
*/
public static void main(String[] args) {
// final int[] ticket = {100};
Runnable ru=new Runnable() {
private int ticket=100;
@Override
public void run() {
while(true){
if(ticket >0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ ticket +"张票");
ticket--;
}
}
}
};
Thread th1=new Thread(ru,"一号窗口");
Thread th2=new Thread(ru,"二号窗口");
Thread th3=new Thread(ru,"三号窗口");
th1.start();
th2.start();
th3.start();
}
}
多个窗口卖同一张票,显然是不合理的。
解决方法
1.同步代码块
使用synchronized关键字构建同步代码块;把可能会产生线程安全问题的代码放入;其中的参数为任意对象,但多个线程要保持参数一致。
Object obj=new Object();
//任意对象
@Override
public void run() {
while(true){
synchronized (obj){
if(ticket >0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ ticket +"张票");
ticket--;
}
}
}
}
2.同步方法
Runnable ru=new Runnable() {
private int ticket=100;
Object obj=new Object();
@Override
public void run() {
while(true){
TicketPay();
}
}
public synchronized void TicketPay() {
if(ticket >0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ ticket +"张票");
ticket--;
}
}
};
3.静态同步方法
其中静态同步方法的同步锁为类名.class;非静态方法的同步锁为this,即调用对象;
public class Runableimpl implements Runnable{
private static int ticket=100;
@Override
public void run() {
while(true){
TicketPay();
}
}
private static void TicketPay() {
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
ticket--;
}
}
}
4.用Lock锁
Runnable ru=new Runnable() {
private int ticket=100;
Object obj=new Object();
@Override
Lock lock=new ReentrantLock();
public void run() {
while(true){
lock.lock();
if(ticket >0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ ticket +"张票");
ticket--;
}
lock.unlock();
}
}
};