一篇文章帶你瞭解HTML格式化元素
阿新 • • 發佈:2020-11-18
1. 執行緒的三種建立方式
1.1 Callable 介面實現
public class CallableDemo implements Callable { @Override public Object call() throws Exception { return null; } @Override public void run() { System.out.println("runnable 實現的執行緒"); } public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newFixedThreadPool(2); Callable callable = new CallableDemo(); Future<String> t1 = executor.submit(callable); String s = t1.get(); System.out.println("開始消費"); } }
1.2 繼承Thread 介面
public class Threaddemo extends Thread {
@Override
public void run() {
System.out.println("hello");
}
public static void main(String[] args) {
new Threaddemo().start();
}
}
1.3 實現runnable 介面
public class CallableDemo implements Runnable { @Override public void run() { System.out.println("runnable 實現的執行緒"); } public static void main(String[] args) { Thread thread = new Thread(new CallableDemo()); thread.start(); } }
2. 執行緒的生命週期
3. 執行緒的基本操作
jion 阻塞主執行緒例項
public class Demo3 implements Runnable{ static int num; @Override public void run() { for (int i = 0; i < 20000; i++) { num++; } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10; i++) { Thread thread = new Thread(new Demo3()); thread.start(); // thread.join(); //阻塞主執行緒,執行緒卓個執行 //阻塞主執行緒,卓個建立子執行緒執行,減少併發 } Thread.sleep(2000); System.out.println(num); } }
1. join 阻塞的是主執行緒
2. 因為多執行緒的執行是非同步的,如果寫程式碼時候,如果不阻塞主執行緒,有時候資料操作的值輸出並不完整
wait notify 例項
main
public class Demo {
public static void main(String[] args) throws InterruptedException {
Queue<Integer> queue = new LinkedList<>();
new Thread(new Puroduce(queue,100)).start();
new Thread(new Consumer(queue,100)).start();
Thread.sleep(1000);
// 生產者一直生產, 直到到達100個,停止生產,阻塞 ---》 通知消費者消費
// 消費者一直消費,沒有可以消費的, 就停止消費, 阻塞;---》 通知生產者生產
}
}
生產者
public class Puroduce implements Runnable {
Queue<Integer> queue;
private int size;
public Puroduce(Queue<Integer> queue, int size) {
this.queue = queue;
this.size = size;
}
private void produce() throws Exception {
int i = 0;
while (true) {
i++;
synchronized (queue) {
while (queue.size() == size) {
System.out.println("已經滿了");
queue.wait();
}
queue.add(i);
System.out.println("生產者開始生產: " + i);
Thread.sleep(100);
queue.notifyAll();
}
}
}
@Override
public void run() {
try {
produce();
} catch (Exception e) {
e.printStackTrace();
}
}
}
消費者
public class Consumer implements Runnable {
Queue<Integer> queue;
private int size = 0;
public Consumer(Queue<Integer> queue, int size) {
this.queue = queue;
this.size = size;
}
private void sonsume() throws Exception {
int i = 0;
synchronized (queue) {
while (true) {
i++;
while (queue.isEmpty()){
System.out.println("已經消費完了");
queue.wait();
}
Integer remove = queue.remove();
System.out.println("消費者開始消費: " + remove);
Thread.sleep(100);
queue.notifyAll();
}
}
}
@Override
public void run() {
try {
sonsume();
} catch (Exception e) {
e.printStackTrace();
}
}
}
總結
synchronized 物件鎖 鎖住同樣一個物件 讓兩個執行緒相互通訊
sleep
interrupter
4. 執行緒安全問題
使用多執行緒帶來的麻煩 原子性 可見性 有序性
4. 1 原子性 例項
public class Demo extends Thread {
private static int num=100000;
@Override
public void run() {
addNumber();
}
// 如果不加synchronized 由於cpu的時間片的切換,有的減法操作丟失了他的執行權力,再次執行時資料產生偏差
[synchronized] static public void addNumber() {
for (int i1 = 0; i1 < 5000; i1++) {
num--;
}
}
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[20];
for (int i = 0; i < threads.length; i++) {
new Thread(new Demo()).start();
}
System.out.println( "結果:" + num);
}
}
4. 2 可見性 例項
public class Demo {
// volatile 使flag 可以被其他執行緒可見
static volatile boolean flag =true;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
int i =0;
while (flag) {
i++;
}
}
).start();
Thread.sleep(1000); //主執行緒不成睡,會直接執行結束,不會顯示答案
flag=false;
}
4. 3 有序性 例項
CPU 的編譯,指令優化會破壞語句的執行順序
5. 解決的方法
5. 1 synchronized 物件鎖用法
-
同步方法
-
同步靜態方法
synchronized static (this) {//物件 }
-
同步方法塊
synchronized (this) { }
5.2 synchronized 物件鎖例項
public class Demo3 implements Runnable{
static int num;
synchronized static void add() { // 若果不是靜態的方法,每一個物件一個方法,就不是爭用資源,鎖不住。
for (int i = 0; i < 20000; i++) {
num++;
}
}
@Override
public void run() {
add();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Demo3());
thread.start();
}
Thread.sleep(2000);
System.out.println(num);
}
}
6. JUC 包和AQS
重入鎖ReentrantLock
public class Demo3 implements Runnable{
static int num;
static ReentrantLock lock = new ReentrantLock(); // 可以鎖住非非靜態方法
void add() {
lock.lock();
for (int i = 0; i < 20000; i++) {
num++;
}
lock.unlock();
}
@Override
public void run() {
add();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Demo3());
thread.start();
}
Thread.sleep(2000);
System.out.println(num);
}
}
重入鎖的意思,就是一個物件在訪問多個爭用資源時候,拿到了相同的鎖之後,就不用再去獲得鎖
如果是共享鎖,物件在訪問多個爭用資源的時候,獲得了一個鎖,別的物件沒有鎖不能訪問該資源,而訪問第二個爭用資源時,又沒有先釋放鎖,造成了死鎖現象。
7. java 中如何使用執行緒池
7.1執行緒池的類別
7.1執行緒池的使用方法 Executors.newFixedThreadPool 例項
public class Demo4 implements Runnable{
static int num;
synchronized static void add() {
for (int i = 0; i < 20000; i++) {
num++;
}
}
@Override
public void run() {
add();
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
for (int i = 0; i < 3; i++) {//啟動3個任務
executorService.execute(new Demo4());
}
Thread.sleep(200);
System.out.println("最終結果: "+ num);
executorService.shutdownNow();
}
}