


Java-Multithread-Parallelit?tsprobleme, die durch den Erhalt des WeChat-Zugriffstokens verursacht werden
Feb 28, 2017 am 09:44 AMHintergrund:
access_token ist das weltweit eindeutige Ticket des offiziellen Kontos. Das access_token ist erforderlich, wenn das offizielle Konto jede Schnittstelle aufruft. Entwickler müssen es ordnungsgem?? speichern. Für die Speicherung des access_token müssen mindestens 512 Zeichen Platz reserviert werden. Die Gültigkeitsdauer von access_token betr?gt derzeit 2 Stunden und muss regelm??ig aktualisiert werden. Wiederholte Erfassung führt dazu, dass das letzte access_token ungültig wird.
1、為了保密appsecrect,第三方需要一個(gè)access_token獲取和刷新的中控服務(wù)器。而其他業(yè)務(wù)邏輯服務(wù)器所使用的access_token均來(lái)自于該中控服務(wù)器,不應(yīng)該各自去刷新,否則會(huì)造成access_token覆蓋而影響業(yè)務(wù); 2、目前access_token的有效期通過(guò)返回的expire_in來(lái)傳達(dá),目前是7200秒之內(nèi)的值。中控服務(wù)器需要根據(jù)這個(gè)有效時(shí)間提前去刷新新access_token。在刷新過(guò)程中,中控服務(wù)器對(duì)外輸出的依然是老access_token,此時(shí)公眾平臺(tái)后臺(tái)會(huì)保證在刷新短時(shí)間內(nèi),新老access_token都可用,這保證了第三方業(yè)務(wù)的平滑過(guò)渡; 3、access_token的有效時(shí)間可能會(huì)在未來(lái)有調(diào)整,所以中控服務(wù)器不僅需要內(nèi)部定時(shí)主動(dòng)刷新,還需要提供被動(dòng)刷新access_token的接口,這樣便于業(yè)務(wù)服務(wù)器在API調(diào)用獲知access_token已超時(shí)的情況下,可以觸發(fā)access_token的刷新流程。 簡(jiǎn)單起見(jiàn),使用一個(gè)隨servlet容器一起啟動(dòng)的servlet來(lái)實(shí)現(xiàn)獲取access_token的功能,具體為:因?yàn)樵搒ervlet隨著web容器而啟動(dòng),在該servlet的init方法中觸發(fā)一個(gè)線程來(lái)獲得access_token,該線程是一個(gè)無(wú)線循環(huán)的線程,每隔2個(gè)小時(shí)刷新一次access_token。相關(guān)代碼如下: :
public class InitServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void init(ServletConfig config) throws ServletException { new Thread(new AccessTokenThread()).start(); } }
2) Thread-Code :
public class AccessTokenThread implements Runnable { public static AccessToken accessToken; @Override public void run() { while(true) { try{ AccessToken token = AccessTokenUtil.freshAccessToken(); // 從微信服務(wù)器刷新access_token if(token != null){ accessToken = token; }else{ System.out.println("get access_token failed------------------------------"); } }catch(IOException e){ e.printStackTrace(); } try{ if(null != accessToken){ Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒 }else{ Thread.sleep(60 * 1000); // 如果access_token為null,60秒后再獲取 } }catch(InterruptedException e){ try{ Thread.sleep(60 * 1000); }catch(InterruptedException e1){ e1.printStackTrace(); } } } } }
3) AccessToken-Code :
public class AccessToken { private String access_token; private long expire_in; // access_token有效時(shí)間,單位為妙 public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public long getExpire_in() { return expire_in; } public void setExpire_in(long expire_in) { this.expire_in = expire_in; } }
4) Servlet in web.xml-Konfiguration
<servlet> <servlet-name>initServlet</servlet-name> <servlet-class>com.sinaapp.wx.servlet.InitServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet>
Da das initServlet ?load-on-startup=0“ setzt, wird es garantiert vor allen anderen Servlets gestartet.
Andere Servlets, die access_token verwenden m?chten, müssen nur AccessTokenThread.accessToken aufrufen.
Führt zu Multi-Thread-Parallelit?tsproblemen :
1) Es scheint kein Problem mit der obigen Implementierung zu geben, aber wenn Sie darüber nachdenken Achten Sie darauf, dass das AccessToken in der AccessTokenThread-Klasse das Problem des gleichzeitigen Zugriffs hat. Es wird nur alle 2 Stunden von AccessTokenThread aktualisiert, aber es werden viele Threads zum Lesen vorhanden sein. Es ist ein typisches Szenario, in dem mehr gelesen und weniger geschrieben wird. und nur ein Thread schreibt. Da es gleichzeitige Lese- und Schreibvorg?nge gibt, muss ein Problem mit dem obigen Code vorliegen.
Der einfachste Weg, sich das vorzustellen, ist die Verwendung von synchronisiert:
public class AccessTokenThread implements Runnable { private static AccessToken accessToken; @Override public void run() { while(true) { try{ AccessToken token = AccessTokenUtil.freshAccessToken(); // 從微信服務(wù)器刷新access_token if(token != null){ AccessTokenThread.setAccessToken(token); }else{ System.out.println("get access_token failed"); } }catch(IOException e){ e.printStackTrace(); } try{ if(null != accessToken){ Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒 }else{ Thread.sleep(60 * 1000); // 如果access_token為null,60秒后再獲取 } }catch(InterruptedException e){ try{ Thread.sleep(60 * 1000); }catch(InterruptedException e1){ e1.printStackTrace(); } } } } public synchronized static AccessToken getAccessToken() { return accessToken; } private synchronized static void setAccessToken(AccessToken accessToken) { AccessTokenThread2.accessToken = accessToken; } }
accessToken wird privat und setAccessToken wird ebenfalls privat ersetzt und hinzugefügt eine synchronisierte Methode für den Zugriff auf accessToken.
Ist es jetzt also perfekt? Gibt es kein Problem? Wenn man darüber nachdenkt, liegt das Problem immer noch in der Definition der AccessToken-Klasse. Sie stellt eine ?ffentliche Set-Methode bereit. Dann k?nnen alle Threads das von allen Threads gemeinsam genutzte AccessToken abrufen ?ndern Sie seine Eigenschaften! ! ! ! Und das ist definitiv falsch und sollte nicht getan werden.
2) L?sung 1:
Wir lassen die AccessTokenThread.getAccessToken()-Methode eine Kopie des accessToken-Objekts zurückgeben, so dass die anderen Der Thread kann das accessToken in der AccessTokenThread-Klasse nicht ?ndern. ?ndern Sie einfach die Methode AccessTokenThread.getAccessToken() wie folgt:
public synchronized static AccessToken getAccessToken() { AccessToken at = new AccessToken(); at.setAccess_token(accessToken.getAccess_token()); at.setExpire_in(accessToken.getExpire_in()); return at; }
Sie k?nnen die Klonmethode auch in der AccessToken-Klasse implementieren. Die Prinzipien sind die gleichen . Natürlich ist setAccessToken auch privat geworden.
3) L?sung zwei :
Da wir nicht zulassen sollten, dass das AccessToken-Objekt ge?ndert wird, warum definieren wir dann nicht accessToken als ?Unver?nderliche Objekte“? Die relevanten ?nderungen sind wie folgt:
public class AccessToken { private final String access_token; private final long expire_in; // access_token有效時(shí)間,單位為妙 public AccessToken(String access_token, long expire_in) { this.access_token = access_token; this.expire_in = expire_in; } public String getAccess_token() { return access_token; } public long getExpire_in() { return expire_in; } }
Wie oben gezeigt, sind alle Eigenschaften von AccessToken als endgültige Typen definiert und es werden nur Konstruktoren und Get-Methoden bereitgestellt . In diesem Fall k?nnen andere Threads es nicht ?ndern, nachdem sie das AccessToken-Objekt erhalten haben. Die ?nderung erfordert, dass das in AccessTokenUtil.freshAccessToken() zurückgegebene AccessToken-Objekt nur über den Konstruktor mit Parametern erstellt werden kann. Gleichzeitig muss setAccessToken von AccessTokenThread auch in privat ge?ndert werden, und getAccessToken muss keine Kopie zurückgeben.
Beachten Sie, dass unver?nderliche Objekte die folgenden drei Bedingungen erfüllen müssen:
a) Der Status des Objekts kann nach seiner Erstellung nicht ge?ndert werden;
b) Alle Felder des Das Objekt ist vom endgültigen Typ. L?sung 3
:
Gibt es eine andere bessere, perfektere und effizientere Methode? Lassen Sie es uns analysieren. In L?sung zwei gibt AccessTokenUtil.freshAccessToken() ein unver?nderliches Objekt zurück und ruft dann die private AccessTokenThread.setAccessToken(AccessToken accessToken)-Methode auf, um den Wert zuzuweisen. Welche Rolle spielt die synchronisierte Synchronisation bei dieser Methode? Da das Objekt unver?nderlich ist und nur ein Thread die setAccessToken-Methode aufrufen kann, spielt die Synchronisierung hier keine Rolle beim ?gegenseitigen Ausschluss“ (da nur ein Thread es ?ndern kann), sondern nur bei der Gew?hrleistung der ?Sichtbarkeit“. Für andere Threads sichtbar, dh andere Threads k?nnen auf das neueste accessToken-Objekt zugreifen. Um die ?Sichtbarkeit“ zu gew?hrleisten, kann flüchtig verwendet werden, daher sollte eine Synchronisierung hier nicht erforderlich sein. Wir verwenden flüchtig, um es zu ersetzen. Der relevante ge?nderte Code lautet wie folgt:
Sie k?nnen ihn auch so ?ndern:public class AccessTokenThread implements Runnable { private static volatile AccessToken accessToken; @Override public void run() { while(true) { try{ AccessToken token = AccessTokenUtil.freshAccessToken(); // 從微信服務(wù)器刷新access_token if(token != null){ AccessTokenThread2.setAccessToken(token); }else{ System.out.println("get access_token failed"); } }catch(IOException e){ e.printStackTrace(); } try{ if(null != accessToken){ Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒 }else{ Thread.sleep(60 * 1000); // 如果access_token為null,60秒后再獲取 } }catch(InterruptedException e){ try{ Thread.sleep(60 * 1000); }catch(InterruptedException e1){ e1.printStackTrace(); } } } } private static void setAccessToken(AccessToken accessToken) { AccessTokenThread2.accessToken = accessToken; } public static AccessToken getAccessToken() { return accessToken; } }Du kannst es auch so ?ndern:
public class AccessTokenThread implements Runnable { private static volatile AccessToken accessToken; @Override public void run() { while(true) { try{ AccessToken token = AccessTokenUtil.freshAccessToken(); // 從微信服務(wù)器刷新access_token if(token != null){ accessToken = token; }else{ System.out.println("get access_token failed"); } }catch(IOException e){ e.printStackTrace(); } try{ if(null != accessToken){ Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒 }else{ Thread.sleep(60 * 1000); // 如果access_token為null,60秒后再獲取 } }catch(InterruptedException e){ try{ Thread.sleep(60 * 1000); }catch(InterruptedException e1){ e1.printStackTrace(); } } } } public static AccessToken getAccessToken() { return accessToken; } }
accesToken變成了public,可以直接是一個(gè)AccessTokenThread.accessToken來(lái)訪問(wèn)。但是為了后期維護(hù),最好還是不要改成public.
其實(shí)這個(gè)問(wèn)題的關(guān)鍵是:在多線程并發(fā)訪問(wèn)的環(huán)境中如何正確的發(fā)布一個(gè)共享對(duì)象。
其實(shí)我們也可以使用Executors.newScheduledThreadPool來(lái)搞定:
public class InitServlet2 extends HttpServlet { private static final long serialVersionUID = 1L; public void init(ServletConfig config) throws ServletException { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); executor.scheduleAtFixedRate(new AccessTokenRunnable(), 0, 7200-200, TimeUnit.SECONDS); } }
public class AccessTokenRunnable implements Runnable { private static volatile AccessToken accessToken; @Override public void run() { try{ AccessToken token = AccessTokenUtil.freshAccessToken(); // 從微信服務(wù)器刷新access_token if(token != null){ accessToken = token; }else{ System.out.println("get access_token failed"); } }catch(IOException e){ e.printStackTrace(); } } public static AccessToken getAccessToken() { while(accessToken == null){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } return accessToken; } }
獲取accessToken方式變成了:AccessTokenRunnable.getAccessToken();
?更多由獲取微信access_token引出的Java多線程并發(fā)問(wèn)題相關(guān)文章請(qǐng)關(guān)注PHP中文網(wǎng)!

Hei?e KI -Werkzeuge

Undress AI Tool
Ausziehbilder kostenlos

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?er Artikel

Hei?e Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

PHP ist eine Open-Source-Skriptsprache, die in der Webentwicklung und serverseitigen Programmierung, insbesondere in der WeChat-Entwicklung, weit verbreitet ist. Heutzutage beginnen immer mehr Unternehmen und Entwickler, PHP für die WeChat-Entwicklung zu verwenden, da es sich zu einer wirklich leicht zu erlernenden und benutzerfreundlichen Entwicklungssprache entwickelt hat. Bei der WeChat-Entwicklung sind die Nachrichtenverschlüsselung und -entschlüsselung ein sehr wichtiges Thema, da sie die Datensicherheit betreffen. Bei Nachrichten ohne Verschlüsselungs- und Entschlüsselungsmethoden k?nnen Hacker leicht an die Daten gelangen, was eine Bedrohung für Benutzer darstellt.

Bei der Entwicklung ?ffentlicher WeChat-Konten wird h?ufig die Abstimmungsfunktion verwendet. Die Voting-Funktion ist eine tolle M?glichkeit für Nutzer, sich schnell an Interaktionen zu beteiligen und ist darüber hinaus ein wichtiges Tool für die Durchführung von Veranstaltungen und Meinungsumfragen. In diesem Artikel erfahren Sie, wie Sie PHP zur Implementierung der WeChat-Abstimmungsfunktion verwenden. Holen Sie sich die Autorisierung des offiziellen WeChat-Kontos. Zuerst müssen Sie die Autorisierung des offiziellen WeChat-Kontos einholen. Auf der ?ffentlichen WeChat-Plattform müssen Sie die API-Adresse des ?ffentlichen WeChat-Kontos, des offiziellen Kontos und des dem ?ffentlichen Konto entsprechenden Tokens konfigurieren. Bei unserer Entwicklung mit der PHP-Sprache müssen wir den von WeChat offiziell bereitgestellten PH verwenden

Mit der Popularit?t von WeChat beginnen immer mehr Unternehmen, es als Marketinginstrument zu nutzen. Die WeChat-Gruppen-Messaging-Funktion ist für Unternehmen eines der wichtigen Mittel zur Durchführung von WeChat-Marketing. Wenn Sie sich jedoch nur auf den manuellen Versand verlassen, ist dies für Vermarkter eine ?u?erst zeitaufw?ndige und mühsame Aufgabe. Daher ist es besonders wichtig, ein WeChat-Massen-Messaging-Tool zu entwickeln. In diesem Artikel wird erl?utert, wie Sie mit PHP WeChat-Massen-Messaging-Tools entwickeln. 1. Vorbereitungsarbeiten Um WeChat-Massen-Messaging-Tools zu entwickeln, müssen wir die folgenden technischen Punkte beherrschen: Grundkenntnisse der PHP-Entwicklung der ?ffentlichen WeChat-Plattform Entwicklungstools: Sub

WeChat ist derzeit eine der sozialen Plattformen mit der gr??ten Nutzerbasis weltweit. Mit der Popularit?t des mobilen Internets beginnen immer mehr Unternehmen die Bedeutung des WeChat-Marketings zu erkennen. Bei der Durchführung von WeChat-Marketing ist der Kundenservice ein entscheidender Bestandteil. Um das Kundenservice-Chatfenster besser verwalten zu k?nnen, k?nnen wir die PHP-Sprache für die WeChat-Entwicklung verwenden. 1. Einführung in die PHP-WeChat-Entwicklung PHP ist eine serverseitige Open-Source-Skriptsprache, die im Bereich der Webentwicklung weit verbreitet ist. In Kombination mit der Entwicklungsschnittstelle der ?ffentlichen WeChat-Plattform k?nnen wir die PHP-Sprache zur Durchführung von WeChat verwenden

Bei der Entwicklung ?ffentlicher WeChat-Konten ist die Benutzer-Tag-Verwaltung eine sehr wichtige Funktion, die es Entwicklern erm?glicht, ihre Benutzer besser zu verstehen und zu verwalten. In diesem Artikel wird erl?utert, wie Sie mit PHP die WeChat-Benutzer-Tag-Verwaltungsfunktion implementieren. 1. Erhalten Sie die OpenID des WeChat-Benutzers. Bevor wir die WeChat-Benutzer-Tag-Verwaltungsfunktion verwenden, müssen wir zun?chst die OpenID des Benutzers abrufen. Bei der Entwicklung ?ffentlicher WeChat-Konten ist es üblich, die OpenID durch Benutzerautorisierung zu erhalten. Nachdem die Benutzerautorisierung abgeschlossen ist, k?nnen wir den Benutzer über den folgenden Code abrufen

Da WeChat zu einem immer wichtigeren Kommunikationsmittel im Leben der Menschen wird, wird seine agile Messaging-Funktion schnell von einer gro?en Anzahl von Unternehmen und Einzelpersonen bevorzugt. Für Unternehmen ist die Entwicklung von WeChat zu einer Marketingplattform zu einem Trend geworden, und die Bedeutung der WeChat-Entwicklung ist nach und nach immer wichtiger geworden. Unter diesen wird die Gruppensendefunktion noch h?ufiger verwendet. Wie implementiert man als PHP-Programmierer Datens?tze zum Senden von Gruppennachrichten? Im Folgenden erhalten Sie eine kurze Einführung. 1. Verstehen Sie die Entwicklungskenntnisse im Zusammenhang mit ?ffentlichen WeChat-Konten, bevor Sie verstehen, wie Datens?tze zum Senden von Gruppennachrichten implementiert werden

So verwenden Sie PHP zur Entwicklung ?ffentlicher WeChat-Konten. ?ffentliche WeChat-Konten sind für viele Unternehmen zu einem wichtigen Kanal für Werbung und Interaktion geworden. PHP als h?ufig verwendete Websprache kann auch zur Entwicklung ?ffentlicher WeChat-Konten verwendet werden. In diesem Artikel werden die spezifischen Schritte zur Verwendung von PHP zum Entwickeln ?ffentlicher WeChat-Konten vorgestellt. Schritt 1: Erhalten Sie das Entwicklerkonto des offiziellen WeChat-Kontos. Bevor Sie mit der Entwicklung des offiziellen WeChat-Kontos beginnen, müssen Sie ein Entwicklerkonto des offiziellen WeChat-Kontos beantragen. Informationen zum spezifischen Registrierungsprozess finden Sie auf der offiziellen Website der ?ffentlichen WeChat-Plattform

Mit der Entwicklung des Internets und mobiler Smart-Ger?te ist WeChat zu einem unverzichtbaren Bestandteil im sozialen Bereich und im Marketing geworden. In diesem zunehmend digitalen Zeitalter ist die Verwendung von PHP für die WeChat-Entwicklung zum Fokus vieler Entwickler geworden. In diesem Artikel werden haupts?chlich die relevanten Wissenspunkte zur Verwendung von PHP für die WeChat-Entwicklung sowie einige Tipps und Vorsichtsma?nahmen vorgestellt. 1. Vorbereitung der Entwicklungsumgebung Bevor Sie WeChat entwickeln, müssen Sie zun?chst die entsprechende Entwicklungsumgebung vorbereiten. Insbesondere müssen Sie die PHP-Betriebsumgebung und die ?ffentliche WeChat-Plattform installieren
