Heim WeChat-Applet WeChat-Entwicklung Java-Multithread-Parallelitätsprobleme, die durch den Erhalt des WeChat-Zugriffstokens verursacht werden

Java-Multithread-Parallelitätsprobleme, die durch den Erhalt des WeChat-Zugriffstokens verursacht werden

Feb 28, 2017 am 09:44 AM
微信开发

Hintergrund:

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,第三方需要一个access_token获取和刷新的中控服务器。而其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则会造成access_token覆盖而影响业务;
2、目前access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器对外输出的依然是老access_token,此时公众平台后台会保证在刷新短时间内,新老access_token都可用,这保证了第三方业务的平滑过渡;
3、access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。

简单起见,使用一个随servlet容器一起启动的servlet来实现获取access_token的功能,具体为:因为该servlet随着web容器而启动,在该servlet的init方法中触发一个线程来获得access_token,该线程是一个无线循环的线程,每隔2个小时刷新一次access_token。相关代码如下:
:
Nach dem Login kopieren

public class InitServlet extends HttpServlet 
{
	private static final long serialVersionUID = 1L;

	public void init(ServletConfig config) throws ServletException 
	{
		new Thread(new AccessTokenThread()).start();  
	}

}
Nach dem Login kopieren

2) Thread-Code :

public class AccessTokenThread implements Runnable 
{
	public static AccessToken accessToken;
	
	@Override
	public void run() 
	{
		while(true) 
		{
			try{
				AccessToken token = AccessTokenUtil.freshAccessToken();	// 从微信服务器刷新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();
				}
			}
		}
	}
}
Nach dem Login kopieren

3) AccessToken-Code :

public class AccessToken 
{
	private String access_token;
	private long expire_in;		// access_token有效时间,单位为妙
	
	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;
	}
}
Nach dem Login kopieren

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>
Nach dem Login kopieren

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();	// 从微信服务器刷新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;
	}
}
Nach dem Login kopieren

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;
	}
Nach dem Login kopieren

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有效时间,单位为妙
	
	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;
	}
}
Nach dem Login kopieren

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();	// 从微信服务器刷新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;
        }
}
Nach dem Login kopieren

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();	// 从微信服务器刷新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;
	}
}
Nach dem Login kopieren

accesToken变成了public,可以直接是一个AccessTokenThread.accessToken来访问。但是为了后期维护,最好还是不要改成public.

其实这个问题的关键是:在多线程并发访问的环境中如何正确的发布一个共享对象。

其实我们也可以使用Executors.newScheduledThreadPool来搞定:

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);
    }
}
Nach dem Login kopieren

public class AccessTokenRunnable implements Runnable 
{    private static volatile AccessToken accessToken;
    
    @Override    public void run() 
    {        try{
            AccessToken token = AccessTokenUtil.freshAccessToken();    // 从微信服务器刷新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;
    }
    
}
Nach dem Login kopieren

获取accessToken方式变成了:AccessTokenRunnable.getAccessToken();

 更多由获取微信access_token引出的Java多线程并发问题相关文章请关注PHP中文网!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

PHP WeChat-Entwicklung: So implementieren Sie die Nachrichtenverschlüsselung und -entschlüsselung PHP WeChat-Entwicklung: So implementieren Sie die Nachrichtenverschlüsselung und -entschlüsselung May 13, 2023 am 11:40 AM

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.

Verwendung von PHP zur Entwicklung von WeChat-Massen-Messaging-Tools Verwendung von PHP zur Entwicklung von WeChat-Massen-Messaging-Tools May 13, 2023 pm 05:00 PM

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

PHP WeChat-Entwicklung: So implementieren Sie die Benutzer-Tag-Verwaltung PHP WeChat-Entwicklung: So implementieren Sie die Benutzer-Tag-Verwaltung May 13, 2023 pm 04:31 PM

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

PHP WeChat-Entwicklung: So implementieren Sie Datensätze zum Senden von Gruppennachrichten PHP WeChat-Entwicklung: So implementieren Sie Datensätze zum Senden von Gruppennachrichten May 13, 2023 pm 04:31 PM

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

PHP WeChat-Entwicklung: So implementieren Sie die Verwaltung von Kundendienst-Chatfenstern PHP WeChat-Entwicklung: So implementieren Sie die Verwaltung von Kundendienst-Chatfenstern May 13, 2023 pm 05:51 PM

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

PHP WeChat-Entwicklung: So implementieren Sie die Abstimmungsfunktion PHP WeChat-Entwicklung: So implementieren Sie die Abstimmungsfunktion May 14, 2023 am 11:21 AM

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

PHP WeChat-Entwicklung: So implementieren Sie die Spracherkennung PHP WeChat-Entwicklung: So implementieren Sie die Spracherkennung May 13, 2023 pm 09:31 PM

Mit der Popularität des mobilen Internets nutzen immer mehr Menschen WeChat als soziale Software, und die offene WeChat-Plattform hat auch Entwicklern viele Möglichkeiten eröffnet. In den letzten Jahren hat sich die Spracherkennungstechnologie mit der Entwicklung der Technologie der künstlichen Intelligenz allmählich zu einer der beliebtesten Technologien in der Entwicklung mobiler Endgeräte entwickelt. In der WeChat-Entwicklung ist die Implementierung der Spracherkennung für viele Entwickler zu einem Problem geworden. In diesem Artikel wird erläutert, wie Sie mit PHP WeChat-Anwendungen entwickeln und Spracherkennungsfunktionen implementieren. 1. Prinzipien der Spracherkennung Bevor wir uns mit der Implementierung der Spracherkennung befassen, wollen wir zunächst die Sprache verstehen

Wie verwende ich PHP für die WeChat-Entwicklung? Wie verwende ich PHP für die WeChat-Entwicklung? May 21, 2023 am 08:37 AM

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

See all articles