程序:针对特定功能的代码集合。是死的
进程:正在执行的程序,是活的,是资源分配的最小单位
线程:一个进程可以有多个线程,是CPU调度的最小单位,线程+ 资源=进程
并行:多个CPU同时处理多件事情,强调的是同一时刻
并发:一个CPU同时处理多件事情,强调的是一个时间段
public class ThreadTest {
static class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
/*
main:0
Thread-0:0
main:1
Thread-0:1
main:2
Thread-0:2
main:3
*/
总结:可以看出两个线程是同时执行的,(Thread.currentThread().getName()
用来获取线程名,获取的是不同的线程
package com.lsm;
class MyThread4 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class ThreadMethod3 {
public static void main(String[] args) {
Thread thread = new Thread(new MyThread4());
thread.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
/*
main:0
Thread-0:0
main:1
main:2
main:3
main:4
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
*/
总结:创建一个类实现Runable接口,把这个类的实例传递给Thread构造方法的位置
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Integer sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
System.out.println(i);
sum += i;
}
}
return sum;
}
public static void main(String[] args) {
MyCallable myCallable = new MyCallable();
FutureTask<Integer> task = new FutureTask<Integer>(myCallable);
new Thread(task).start();
try {
Integer result = task.get();
System.out.println("result="+result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
总结:Callable可以有返回值,Callable支持泛型传递返回值,可以抛出异常,使用的时候需要借助FutureTask
。
package com.lsm.java1.MyJava;
import java.util.concurrent.*;
class NumberThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2 == 0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2 != 0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class MyCallable1 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
sum+=i;
}
return sum;
}
}
public class ThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new NumberThread()); //适合Runable
service.execute(new NumberThread1());
FutureTask<Integer> task = new FutureTask<>(new MyCallable1());
Thread thread = new Thread(task);
service.submit(thread);
Integer result = null;
try {
result = task.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("=============="+result);
service.shutdown();
}
}
package com.lsm;
public class ThreadTest {
static class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 2; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
// myThread.start();
myThread.run();
for (int i = 0; i < 2; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
/*
main:0
main:1
main:0
main:1
*/
总结:可以看出都是main线程在执行,run方法在API中是这样介绍的:
start()
导致此线程开始执行; Java虚拟机调用此线程的run
方法。
class MyThread extends Thread{
@Override
public void run() {
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName()+":"+j);
}
}
}
public class ThreadMethod {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
if (i==2){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/*
main:0
Thread-0:0
main:1
main:2
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
main:3
main:4
*/
class MyThread1 extends Thread{
@Override
public void run() {
for (int j = 0; j < 50; j++) {
System.out.println(Thread.currentThread().getName()+":"+j);
}
}
}
public class ThreadMethod1 {
public static void main(String[] args) {
Thread t = new MyThread1();
t.start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
if (i%2 ==0){
Thread.currentThread().yield();
}
}
}
}
/*
Thread-0:9
main:0
Thread-0:10
Thread-0:11
Thread-0:12
Thread-0:13
main:1
main:2
Thread-0:14
main:3
main:4
Thread-0:15
main:5
Thread-0:16
main:6
Thread-0:17
main:7
Thread-0:18
main:8
Thread-0:19
main:9
Thread-0:20
Thread-0:21
Thread-0:22
main:10
Thread-0:23
Thread-0:24
Thread-0:25
Thread-0:26
main:11
main:12
main:13
*/
总结:可以看到main线程调用yield方法后会让出cpu的使用权,让出来自己还会抢占。最后一行main线程执行到12后如何让出条件,让出cpu后main线程再次抢占执行到13
package com.lsm;
class MyThread2 extends Thread{
@Override
public void run() {
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName()+":"+j);
}
}
}
public class ThreadMethod2 {
public static void main(String[] args) {
Thread t = new MyThread2();
t.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
if (i%2 ==0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/*
main:0
Thread-0:0
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
main:1
main:2
main:3
main:4
*/
方法 | 注释 | 作用 |
---|---|---|
public static native void yield(); | A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint. | 当前线程让出CPU,有可能下次还会碰到此线程 |
public final synchronized void setName(String name) | Changes the name of this thread to be equal to the argument | 给线程设置名字 |
public final void join() | Waits for this thread to die. | 插入一个线程,直到插入的线程执行完本线程才会执行 |
public static native void sleep(long millis) | Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does not lose ownership of any monitors | 让当前线程睡眠指定的毫秒,睡眠期间会放弃cpu,睡醒后等待cpu分配时间片 |
public final void setPriority(int newPriority) | Changes the priority of this thread. | 设置当前线程的优先级,并不完全可靠。优先级1-10默认5 |
一个类可以调用多次start方法吗
Thread类中
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
可以看出一个线程多次调用start方法会抛出IllegalThreadStateException
什么时候会发生线程安全问题?
多个线程中有有共享的变量
模拟三个窗口卖票
package com.lsm;
public class Ticket {
public static void main(String[] args) {
Thread t1 = new Thread(new MyWindow(), "1窗口");
Thread t2 = new Thread(new MyWindow(), "2窗口");
Thread t3 = new Thread(new MyWindow(), "3窗口");
t1.start();
t2.start();
t3.start();
}
}
class MyWindow implements Runnable {
private static int ticket = 100; //这里的static代表该类共享变量
private Object obj = new Object();
@Override
public void run() {
synchronized (obj) {
while (true) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
synchronized (锁对象) {
对共享变量的操作
}
public class Ticket2 {
public static void main(String[] args) {
MyWindow2 windows2 = new MyWindow2();
Thread t1 = new Thread(windows2, "1窗口");
Thread t2 = new Thread(windows2, "2窗口");
Thread t3 = new Thread(windows2, "3窗口");
t1.start();
t2.start();
t3.start();
}
}
class MyWindow2 implements Runnable {
static int ticket = 100;
@Override
public void run() {
show();
}
private synchronized void show() {
while (true) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了" + ticket);
ticket--;
} else {
break;
}
}
}
}
总结:同步方法private synchronized void show()
中的锁对象是this也就是MyWindow2
的实例,如果是public static synchronized void show()
锁的是当前类的.class
public class Ticket3 {
public static void main(String[] args) {
MyWindow3 windows3 = new MyWindow3();
Thread t1 = new Thread(windows3, "1窗口");
Thread t2 = new Thread(windows3, "2窗口");
Thread t3 = new Thread(windows3, "3窗口");
t1.start();
t2.start();
t3.start();
}
}
class MyWindow3 implements Runnable {
static int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了" + ticket);
Thread.sleep(10);
ticket--;
} else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
public class Bank {
private Bank(){}; //私有构造方法,不能再外部创建
private static Bank instance = null;
public static Bank getInstance(){
if (instance == null){ //外层判断提高Synchronize的效率
synchronized (Bank.class){
if (instance == null){ //内层判断用于创建对象
instance = new Bank();
}
}
}
return instance;
}
}
public class DeadLock {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
new Thread(()->{
synchronized (o1){
System.out.println("111a");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){
System.out.println("111b");
}
}
}).start();
new Thread(()->{
synchronized (o2){
System.out.println("222a");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
System.out.println("222b");
}
}
}).start();
}
}
运行结果
发现程序停不了了。
死锁产生的原因:
不同的线程占用了对方需要的锁不放弃,在等待对方释放自己需要的锁。
解决方法:
避免锁嵌套
class MyThread extends Thread {
private static int num = 1;
@Override
public void run() {
while (true) {
synchronized (this) {
notify();
if (num <= 100) {
int i = Integer.parseInt(Thread.currentThread().getName()); //获取线程名
if (num % 3 == i) {
System.out.println(Thread.currentThread().getName() + ":" + num);
num++;
}else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}else {
break;
}
}
}
}
}
public class ThreeLock {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread, "0");
Thread thread1 = new Thread(myThread, "1");
Thread thread2 = new Thread(myThread, "2");
thread.start();
thread1.start();
thread2.start();
}
}
总结:进入run方法就随机唤醒一个线程。通过让1-100和3取模,模到哪个就用哪个线程进行直接运行,否则就让当前线程wait
slepp | wait |
---|---|
相同点 | 让线程阻塞 |
声明位置 | Thread类 |
调用位置 | 任何场景 |
锁 | 不会释放锁 |
package com.lsm.java1.MyJava;
public class BoxTest {
public static void main(String[] args) {
Box box = new Box();
Producer1 producer = new Producer1(box);
Consumer1 consumer = new Consumer1(box);
producer.setName("生产者");
consumer.setName("消费者");
producer.start();
consumer.start();
}
}
class Box {
private int productCount = 0;
//生产
public synchronized void produceProduct() {
if (productCount < 20) {
productCount++;
System.out.println(Thread.currentThread().getName() + "生产了,盒子里有" + productCount + "个");
notify();
} else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//消费
public synchronized void consumerProduct() {
if (productCount > 0) {
System.out.println(Thread.currentThread().getName() + "消费了,盒子里有" + (productCount - 1) + "个");
productCount--;
notify();
} else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Producer1 extends Thread {
private Box box;
public Producer1(Box box) {
this.box = box;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
box.produceProduct();
}
}
}
class Consumer1 extends Thread {
private Box box;
public Consumer1(Box box) {
this.box = box;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
box.consumerProduct();
}
}
}
原文:https://www.cnblogs.com/adaobl/p/13817414.html